2012-06-28 24 views
5

Devo integrare alcune macro in un progetto che utilizza un motivo a torta. Questo modello ci ha permesso di evitare miliardi di importazioni, tra gli altri vantaggi, quindi vorremmo tenerlo. Ora, stiamo affrontando un problema con alcuni macro sperimentali che abbiamo testato all'esterno del trunk. In primo luogo, mostriamo un manichino sistema denominato torta:È possibile integrare Cake-Pattern e Macro?

trait APiece { 
    class A 
} 

trait BPiece { this: APiece => 
    def aMacro(a: A): Unit =() /* macro ??? */ 
} 

trait CPiece { this: APiece with BPiece => 
    def aMacroInvoker = aMacro(new A) 
} 

class Cake { this: APiece with BPiece with CPiece => } 

testa definisce una classe, BPiece si suppone che sia una macro che utilizza la classe a testa definito, e, infine, CPiece invoca la macro. Ho detto che BPiece avrebbe dovuto essere una macro dato che non ero in grado di codificare un'implementazione per questo. Ho provato diversi modi ma ho sempre in crash con il seguente errore:

"macro implementation must be in statically accessible object" 

Leggendo il macros code si può intuire che é necessario racchiudere la macro in un modulo statico. C'è un modo per distribuire una macro che utilizza le strutture di sistema?

risposta

4

Fortunatamente c'è una soluzione facile al tuo problema.

Ma prima, lasciatemi dare qualche retrospettiva. Nel primo prototipo, le macro erano definite in questo modo: def macro aMacro(a: A): Unit = .... Una delle scoperte più importanti che abbiamo avuto durante la preparazione di un SIP è la separazione delle definizioni di macro (le facce pubbliche di macro) e le implementazioni di macro (trasformatori di alberi che ospitano la logica macro). Mi ci è voluto un po 'capire quanto è bello questo, ma ora mi rallegro di gioia ogni volta che scrivo una macro dichiarazione.

Quindi, torna alla tua domanda. Certo, le implementazioni di macro devono essere accessibili staticamente (altrimenti, il compilatore non sarà in grado di caricarle e invocarle durante la compilazione). Tuttavia definizioni di macro non hanno questa limitazione, in modo da poter scrivere la definizione del genere:

trait BPiece { this: APiece => 
    def aMacro(a: A): Unit = macro Macros.aMacro 
} 

Macro implementazione che viene indicato dalla definizione può essere messo in qualsiasi oggetto che si desidera, anche in un'unità di compilazione diverso .

L'unico pezzo mancante di puzzle è come fare riferimento a A dall'implementazione, perché A è definito all'interno di una torta. Il modo più semplice sarebbe quello di rendere aMacro generico e fare affidamento su un'inferenza di tipo:

(aggiornamento: per fare questo esempio funziona in 2.10.0-M7, è necessario sostituire c.TypeTag con c.AbsTypeTag; per fare questo esempio il lavoro in 2.10.0-RC1, c.AbsTypeTag deve essere sostituito con c.WeakTypeTag)

trait BPiece { this: APiece => 
    def aMacro[A](a: A): Unit = macro Macros.aMacro[A] 
} 

object Macros { 
    def aMacro[A: c.TypeTag](c: Context)(a: c.Expr[A]): c.Expr[Unit] = c.literalUnit 
} 

Questo non vi permetterà di utilizzare reify, però, perché per una macro implementazione A è solo un parametro di tipo senza qualsiasi membro. Ci saranno anche problemi se vorrai restituire qualcosa di specifico della torta dalla macro, ma affrontiamoli quando si presentano. Per favore, invia domande di follow-up se è necessario.

+2

Non penso che risolva il suo problema, e non credo che succederà niente. L'essenza del modello di torta - come dovresti sapere! :-): è in grado di scegliere i livelli desiderati nel codice "client". Se 'Macro 'è statico, non puoi cambiarlo a piacimento. È possibile cambiare file di origine o file di classe, ma non è possibile scrivere codice che dice "questo utilizzerà le macro da qui e che utilizzerà le macro da lì". –

+0

Ottimo, penso che sorgeranno nuovi problemi, ma ora posso andare avanti con questa soluzione. Grazie mille!Daniel, il nostro sistema non sarà veramente (modello di torta) puro con i macro. Permetteremo al cliente di decidere se vuole usarli o meno. Quindi, spero che questo sia abbastanza buono. – jeslg

+0

@ DanielC.Sobral I però l'idea era di dichiarare una macro all'interno di una torta. Se si dispone di livelli diversi che definiscono macro che si riferiscono a diverse implementazioni di macro, è possibile alternare tra loro come si desidera e ottenere un comportamento diverso. –