2010-08-12 17 views
66

ho letto:A che cosa serve la metaprogrammazione?

e confesso una certa confusione al scopo dietro generazione metaprogrammazione/code.

Qualcuno ha un esempio concreto di dove utilizza metaprogrammazione/generazione di codice? Ancora meglio sarebbe una spiegazione di accompagnamento del motivo per cui era meglio di un'alternativa.

modificare: Sarebbe Thistle essere considerato metaprogrammazione?

+1

Il tuo secondo link sembra abbastanza chiaro, qual è la tua comprensione dei due concetti, per vedere se c'è qualche confusione fondamentale da parte tua, altrimenti la tua domanda è IMO troppo ampia e soggettiva. –

+1

La mia domanda è una questione di praticità: perché metaprogrammare meglio di, ad esempio, scrivere alcune parti di query SQL parametrizzate e incollarle in base a determinate condizioni? O * è * che metaprogramming? (Io non * penso * così, ma è per questo che sto facendo la domanda - È diverso e perché è meglio?). –

+1

Perché a volte non sai nemmeno quale tabella stai per interrogare o quali colonne restituirai prima del tempo (forse dipende da una combinazione di input dell'utente, troppo difficile da precalcolare tutte le possibilità prima del tempo), quindi usi l'SQL dinamico (che forse potrebbe essere pensato come una forma di metaprogrammazione). – FrustratedWithFormsDesigner

risposta

103

immaginare un ragazzo che costruisce automobili. Diciamo che è la stessa cosa che usare un computer.
A un certo punto si rende conto che fa sempre la stessa cosa, più o meno.
Quindi costruisce fabbriche per costruire automobili, ed è molto meglio. Sta ora programmando!
Tuttavia, ancora una volta, a un certo punto, si rende conto che fa sempre la stessa cosa, in una certa misura.
Ora decide di costruire fabbriche che costruiscono fabbriche che costruiscono automobili. Questo è metaprogrammazione.

La metaprogrammazione è immensamente potente, ma un problema tecnico nel sistema fa sì che tutti i vantaggi si trasformino in enormi difficoltà. Quindi padroneggia e usalo ... O stai lontano!

+4

Questa è una buona risposta, ma mostra la cosa che trovo più fastidiosa di metaprogrammazione. Quando finisce? Cosa ci impedisce di avere fabbriche che costruiscono fabbriche che costruiscono fabbriche che costruiscono pecore che costruiscono fabbriche che costruiscono fabbriche costruiscono automobili? – XQLRSZ

+1

@XQLRSZ Allo stesso modo in cui sai quando smettere di scrivere qualsiasi codice: quando smette di semplificarti la vita. A meno che tu non stia facendo qualcosa più e più volte, non c'è motivo di estrarlo in un pezzo di codice. –

+0

wow, mai pensato in questo modo: O – Mixone

2

Le librerie basate su metaprogrammazione/codice aiutano a scrivere codice direttamente esplicito e semplice che genererà il codice di dettagli di implementazione per te, in base ai parametri utilizzati.

Boost è pieno di librerie (C++) che dimostrano cosa è possibile ottenere con metaprogrammazione. Alcuni esempi validi (e forse difficili da capire) sono Proto che consentono l'implementazione di DSL, Spirit che consente di scrivere un compilatore utilizzando la grammatica EBNF direttamente all'interno del codice e molte altre librerie di blow-minding.

+3

L'esempio di generazione del codice corrispondente è GNU 'flex' e' bison'. Come Spirit, è usato per creare analizzatori e parser lessicali.Tuttavia, hanno il loro linguaggio che non è C o C++, devono essere eseguiti come un passaggio separato e il loro output deve essere compilato da un compilatore C o C++. Questo illustra la differenza fondamentale tra i generatori di codice e la metaprogrammazione: i generatori di codice fanno il loro lavoro come una fase di "pre-elaborazione" separata, il cui output viene quindi compilato, mentre la metaprogrammazione viene semplicemente compilata in un passo come il resto del codice. –

+0

Non penso che "metaprogramming" o "code generation" siano "fa il compilatore del codice sorgente-oggetto-oggetto" o "è fatto nel mio linguaggio di programmazione primario". Tutto ciò che importa è che il codice che scrivo manualmente viene convertito in qualcosa che viene eseguito. Il "compilatore" può utilmente eseguire metaprogrammazione (seguendo le direttive di metaprogrammazione che ho scritto) in una varietà di fasi, presto, a metà, in ritardo. Ciò che importa è che la metaprogrammazione riguardi la manipolazione del codice che ho scritto, utilizzando il codice aggiuntivo che ho scritto, per produrre il codice finale che viene eseguito. Sì, questo include i generatori di codice IMHO. –

3

mio recente (ultimi 6 mesi) esempio concreto di generazione di codice:

  1. ho uno SQL più script che genera e poi esegue altri script SQL più. Lo script genera esegue query su alcune tabelle che contengono campi di data e ora e, quando ho progettato lo script, era impossibile sapere quale intervallo di tempo selezionare. Quindi, lo script principale fa il suo lavoro, e capisce quali intervalli di tempo devono essere nei sub-script. Quindi genera i pedici scrivendo il loro codice su file (e sostituendo i segnaposto per le ore di inizio e di fine effettive). Finalmente esegue l'indice (s). Ho usato questo trucco per alcune situazioni ora (anche se spesso più complicato di questo) in cui la struttura dei passaggi secondari dipende dai risultati dei precedenti passaggi.

  2. Una volta ho ottenuto un foglio elettronico per mappare gli elementi da un XSD alle colonne di una tabella in un database. È stato possibile generare snippet XSL e completare query dal foglio di calcolo utilizzando macro e VBA. Questi snippet e query sono stati copiati e incollati (per lo più as-is senza modifiche necessarie) nel sistema che li ha eseguiti ed elaborati i risultati. Non è una soluzione carina, ma certamente ha reso un lavoro molto noioso molto meno noioso, e il codice che ne è risultato è stato probabilmente molto più consistente rispetto a se avessi passato una settimana o due scrivendo tutto a mano.

SO elenco di esempi di metaprogrammazione: What are the coolest examples of metaprogramming that you've seen in C++?

18

Penso a metaprogamming come "programmi che scrivono (o modificano) altri programmi". (Un'altra risposta diceva "fabbriche che fabbricano fabbriche", bella analogia).

persone trovare tutti i tipi di usi per questo: le applicazioni di personalizzazione, la generazione di codice standard, ottimizzare un programma per circostanze particolari, DSL attuazione, inserendo il codice per gestire i problemi di progettazione ortogonali ("aspetti") ...

Ciò che è notevole è il modo in cui molti meccanismi sono stati inventati per fare questo frammentario: modelli di testo, macro, condizionali del preprocessore, generici, C++ - modelli, aspetti, riflessione, ... E di solito alcuni di questi meccanismi sono incorporati in alcuni lingue e altri meccanismi in altre lingue e la maggior parte delle lingue non ha alcun supporto per la metaprogrammazione. Questa distribuzione di funzionalità a dispersione significa che potresti essere in grado di fare alcuni tipi di metaprogrammazione in una lingua, con limitazioni, e tuttavia non essere in grado di farlo in un'altra. Ecco aggravante: -}

un'osservazione che ho seguito fino in fondo è che si può costruire generico macchinari metaprogrammazione che funziona con qualsiasi linguaggio in forma di program transformations. Una trasformazione di programma è un modello parametrizzato: "se vedi la sintassi , sostituisci con la sintassi".

Una trasformazione di per sé in genere non è impressionante, ma decine o centinaia possono rendere spettacolari le modifiche allo codice. Poiché le trasformazioni del programma (sofisticate) possono, nell'effetto , simulare una macchina di Turing, possono eseguire modifiche arbitrarie del codice, tra cui tutte quelle tecniche point-wise che si trovano sparse in giro.

Uno strumento che accetta le definizioni di lingua. Trasformazioni specifiche della lingua e genera un altro per applicare quelle trasformazioni è un meta -metaprogramming strumento: un programma per scrivere "programmi che scrivono programmi".

Il valore è che è possibile applicare tale strumento per eseguire un'ampia varietà di modifiche in codice arbitrario. E non hai bisogno del comitato di design linguistico per rendersi conto che hai bisogno di un particolare tipo di supporto per la metaprogrammazione e di affrettarti per fornirtelo così puoi andare avanti con il tuo lavoro oggi.

Una lezione interessante è che tali macchine necessitano di una forte analisi del programma (simbolo tabelle, controllo e analisi del flusso di dati, ecc.) supporto per concentrarsi su dove sono i problemi nel codice, in modo che la metaprogrammazione dei macchinari possa fare qualcosa in quel punto (un esempio molto debole di questo sono le specifiche punto-taglio in aspetti, che dicono "apportare modifiche a posti che assomigliano a questo ").

L'OP ha richiesto esempi specifici su dove è stata applicata la metaprogrammazione. Abbiamo utilizzato il nostro strumento "meta" -metaprogramming (DMS Software Reengineering Toolkit) di svolgere le seguenti attività sul grandi basi di codice automaticamente:

  • migrazione Lingua
  • Implementazione copertura di test e Profilers
  • Clone Implementazione rilevamento
  • architettura Massive reingegnerizzazione
  • generazione
  • codice per il controllo della fabbrica
  • SOAization di controller di rete integrati
  • Architettura di estrazione per il software mainframe
  • Generazione di istruzioni SIMD vettoriali da calcoli di matrice
  • reverse engineering del codice di tornare ai concetti

attraverso molti linguaggi, inclusi Java, C#, C++, PHP, ...

L'OP ha anche chiesto: "Perché è stato meglio dell'alternativa?" La risposta ha a che fare con la scala, il tempo e la precisione.

Per le applicazioni di grandi dimensioni, la dimensione pura della base di codice significa che non si dispone delle risorse o del tempo per effettuare tali analisi o modifiche manualmente.

Per le attività di generazione o ottimizzazione del codice, è possibile eseguire manualmente lo strumento , ma gli strumenti possono farlo molto più rapidamente e con maggiore precisione.

In sostanza, questi strumenti fanno ciò che gli esseri umani semplicemente non possono.

Vale la pena notare che gli strumenti non hanno creatività; hai ancora bisogno degli umani per determinare cosa fare, ad es. per decidere quale attività (vedi sopra l'elenco per gli esempi) e determinare come definire le analisi/trasformazioni per ottenere l'effetto. Hai ancora bisogno di meta -programmatori. Tuttavia, quando un meta-programmatore arma uno strumento con le giuste conoscenze, il codice risultante può essere creato da un programmatore esperto incredibilmente veloce, creativo, come .

3

Posso dare il mio esempio specifico: Sto sviluppando ABSE, che è un approccio di meta-programmazione. Con ABSE crei un modello (in realtà, un albero) in cui ogni oggetto è un "Atomo". Questo Atom rappresenta un "concetto" e contiene i necessari metadati per la sua definizione.

In ABSE, l'implementazione di un concetto è in realtà un "mini-programma".

Quindi, il modellatore host (AtomWeaver, sviluppato insieme a ABSE) prende il modello e "tesse" un programma generatore da tutti i suoi atomi.Quel programma viene quindi eseguito generando gli artefatti desiderati (codice sorgente, dati, ecc.).

Così, il flusso di lavoro ABSE è:

  1. Creare un concetto discreta (una frazione del meta-metaprogramma)
  2. riutilizzo quel concetto in un modello (costruzione in modo efficace la metaprogramma)
  3. Host modellatore tesse ed esegue il metaprogramma
  4. il metaprogramma genera il vostro programma finale

A prima vista Thi s sembra un lavoro ridondante e complesso, ma in realtà è piuttosto semplice se si coglie il concetto.

Vantaggi di meta-programmazione (non in esclusiva per ABSE) ?:

  • modifica del modello e rigeneranti un sistema completo (Immaginate refactoring dispone invece di linee di sorgente).
  • La modifica di alcune definizioni nel modello può comportare programmi distinti (una famiglia di prodotti software).
  • Riutilizzando i modelli, è possibile modificare il codice del modello, rigenerare e ottenere il codice modificato in dozzine, centinaia di posizioni.
  • Molti altri, davvero

Metaprogrammazione, generazione di codice, il programma di trasformazione sono nuovi mondi eccitanti nello sviluppo del software, IMHO. Tuttavia, metaprogramming richiede una nuova abilità: meta-pensiero.

Possiamo definire meta-pensiero come "pensare a come si pensa al proprio sviluppo". Una specie di riflessione di classe, applicata su te stesso. In pratica, devi scoprire i tuoi modelli di sviluppo, isolarli, renderli generici e poi trasformarli in metaprogrammi usando la tua tecnica preferita, essendo ABSE, DSL, DSM, ecc.

1

Un esempio specifico di dove potrebbe essere un approccio utile

Si dispone di un insieme di classi di terze parti, a cui si desidera aggiungere un comportamento generico - per esempio un qualche tipo di controllo di sicurezza/accesso, mappatura oggetti come JSON, ecc

Si potrebbe scrivere o generare sottoclassi per tutto, aggiungendo metodi wrapper per aggiungere controllo accessi e chiamare la superclasse. Con la meta-programmazione, è possibile farlo in fase di esecuzione e anche le modifiche verranno automaticamente applicate a tutte le classi di terze parti aggiuntive/modificate.

Con l'esempio JSON, utilizzando l'introspezione della classe si dovrebbe essere in grado di generare il codice per serializzare un oggetto e quindi aggiungerlo come metodo alla classe. Gli altri estremi generano o scrivono il codice in anticipo (prima della compilazione) e hanno un impatto ogni volta che la classe cambia, o un approccio completamente generico che utilizza l'introspezione su ogni singolo oggetto, ogni volta che si desidera mapparlo.

A seconda della lingua e del tempo di esecuzione in questione, un approccio di metaprogamming è probabilmente più veloce di quello generico/introspettivo, ma più lento di quello anticipato, poiché si riducono molte ricerche di dati nel codice.

Laddove la meta-programmazione non esiste direttamente in una lingua, mi sembra anche che sia spesso reinventata attraverso gli schemi (es.Contenitori in stile IoC come la primavera).

5

Ho ottenuto il massimo utilizzo dalla metaprogrammazione per il bridging tra diverse API.

Un esempio di funzionamento sarebbe FireBreaths JSAPIAuto che facilita la scrittura di classi C++ esposte a JavaScript. Fornendo una funzionalità di registrazione per le funzioni che devono essere esposte, i tipi di argomenti possono essere controllati e da quel codice di adattamento generato in fase di compilazione che converte dai tipi API di script a tipi C++ nativi e viceversa, anche supportando direttamente map , vector, ecc

Come semplice esempio, si consideri un esposto add(a, b) funzione che utilizza alcuni tipi di script API:

ScriptVariant add(const std::vector<ScriptVariant>& values) { 
    // have to check argument count 
    if(values.size() != 2) 
     throw script_error("wrong number of arguments"); 

    try { 
     // have to convert from scripting-API types 
     long a = values[0].convert_cast<long>(); 
     long b = values[0].convert_cast<long>(); 
     return a+b; // potentially need to convert back too 
    } catch(ScriptVariant::bad_cast& e) { 
     // need to handle conversion failure 
     throw script_error("conversion failed :("); 
    } 
} 

La logica effettiva sepolto in c'è solo una linea, che i controlli e le conversioni sono fastidiosi e ridondante. Con l'iscrizione-impianto già citato (ad esempio, nel costruttore):

registerMethod("add", make_method(this, &MyClass::add)); 

questo ora può essere semplicemente scritto come:

long add(long a, long b) { 
    return a+b; 
} 

... e il quadro si occupa di generare il codice per neccessary tu.

1: anche se vorrei fare realizzazione un po 'più pulito ... ... se avrei dovuto ricominciare da capo

0

si poteva guardare le macro di Common Lisp o modelli C++ s' e vedere come vengono utilizzati . Entrambi sono metaprogrammazione nel senso che stai usando. Troverete che entrambi sono utilizzati pesantemente in un sacco di codice.

Le macro Lisp vengono spesso utilizzate per ridefinire la lingua. Ad esempio, l'ultimo capitolo di Paul Graham On Lisp crea un'estensione orientata agli oggetti funzionante per Common Lisp. Un altro esempio è l'ora defunto Garnet.

La vecchia libreria di modelli standard per C++ (principalmente incorporata nella libreria standard) era un modo di introdurre un gran numero di contenitori e algoritmi che funzionavano come se fossero stati integrati nella lingua, almeno in termini di integrazione ed efficienza (non sintatticamente).

1

Avvia il tuo Visual Studio (Eclipse, Netbeans, qualsiasi altra cosa). Crea un nuovo progetto. Sorpresa: hai appena usato alcune metaprogrammazione, creando un progetto da un modello. Non è pratico?