Cos'è esattamente la metaprogrammazione?


128

Stavo leggendo un articolo su TheServerSide sulla programmazione ployglot sulla piattaforma Java . Alcuni commenti nell'articolo si riferiscono alla metaprogrammazione come alla capacità di generare codice (forse al volo).

Sta metaprogrammando la capacità di generare codice al volo o è la capacità di iniettare metodi e attributi in oggetti esistenti in fase di runtime (come quello che consentono alcuni linguaggi dinamici come Python, Ruby e Groovy).


7
Si potrebbe essere interessati a questa risposta stackoverflow.com/questions/2565572/...
ewernli

@ewernli: Questa risposta è effettivamente migliore di qualsiasi altra risposta qui!
JD

Risposte:


100

La metaprogrammazione si riferisce a una varietà di modi in cui un programma conosce se stesso o può manipolarsi.

In linguaggi come C #, la riflessione è una forma di metaprogrammazione poiché il programma può esaminare le informazioni su se stesso. Ad esempio restituendo un elenco di tutte le proprietà di un oggetto.

In linguaggi come ActionScript, puoi valutare le funzioni in fase di runtime per creare nuovi programmi come eval ("x" + i). DoSomething () influenzerebbe un oggetto chiamato x1 quando i è 1 e x2 quando i è 2.

Infine, un'altra forma comune di metaprogrammazione è quando il programma può cambiare se stesso in modi non banali. LISP è ben noto per questo ed è qualcosa che Paul Graham ha sostenuto circa un decennio fa. Dovrò cercare alcuni dei suoi saggi specifici. Ma l'idea è che il programma cambierebbe un'altra parte del programma in base al suo stato. Ciò consente un livello di flessibilità per prendere decisioni in fase di esecuzione che è molto difficile oggi nelle lingue più diffuse.

Vale anche la pena notare che nei bei vecchi tempi della programmazione in assembly diretto, i programmi che si alteravano in fase di esecuzione erano necessari e molto comuni.

Dal saggio di Paul Graham "What Made Lisp Different" :

Molte lingue hanno qualcosa chiamato macro. Ma le macro Lisp sono uniche. E che tu ci creda o no, quello che fanno è legato alle parentesi. I progettisti di Lisp non hanno messo tutte quelle parentesi nella lingua solo per essere diversi. Per il programmatore Blub, il codice Lisp sembra strano. Ma quelle parentesi ci sono per un motivo. Sono la prova esteriore di una differenza fondamentale tra Lisp e altre lingue.

Il codice Lisp è composto da oggetti dati Lisp. E non nel senso banale che i file di origine contengono caratteri e le stringhe sono uno dei tipi di dati supportati dal linguaggio. Il codice Lisp, dopo essere stato letto dal parser, è costituito da strutture di dati che puoi attraversare.

Se capisci come funzionano i compilatori, quello che sta realmente succedendo non è tanto che Lisp ha una sintassi strana quanto che Lisp non ha sintassi. Scrivete programmi negli alberi di analisi che vengono generati all'interno del compilatore quando vengono analizzati altri linguaggi. Ma questi alberi di analisi sono completamente accessibili ai tuoi programmi. Puoi scrivere programmi che li manipolano. In Lisp, questi programmi sono chiamati macro. Sono programmi che scrivono programmi.

Programmi che scrivono programmi? Quando mai vorresti farlo? Non molto spesso, se pensi in Cobol. Tutto il tempo, se pensi in Lisp. Sarebbe conveniente qui se potessi fare un esempio di una potente macro, e dire lì! che ne dici di quello? Ma se lo facessi, sembrerebbe semplicemente incomprensibile a qualcuno che non conosce Lisp; non c'è spazio qui per spiegare tutto ciò che avresti bisogno di sapere per capire cosa significava. In Ansi Common Lisp ho cercato di spostare le cose il più velocemente possibile, e anche così non sono arrivato alle macro fino a pagina 160.

Ma penso di poter fornire una sorta di argomento che potrebbe essere convincente. Il codice sorgente dell'editor di Viaweb era probabilmente circa il 20-25% di macro. Le macro sono più difficili da scrivere rispetto alle normali funzioni Lisp, ed è considerato un cattivo stile usarle quando non sono necessarie. Quindi ogni macro in quel codice è lì perché deve esserci. Ciò significa che almeno il 20-25% del codice in questo programma fa cose che non puoi fare facilmente in nessun altro linguaggio. Per quanto scettico possa essere il programmatore di Blub riguardo alle mie affermazioni sui misteriosi poteri del Lisp, questo dovrebbe incuriosirlo. Non stavamo scrivendo questo codice per il nostro divertimento. Eravamo una piccola startup, programmando il più duramente possibile per mettere barriere tecniche tra noi ei nostri concorrenti.

Una persona sospettosa potrebbe iniziare a chiedersi se ci fosse qualche correlazione qui. Una grossa fetta del nostro codice stava facendo cose che sono molto difficili da fare in altre lingue. Il software risultante ha fatto cose che il software dei nostri concorrenti non poteva fare. Forse c'era qualche tipo di connessione. Ti incoraggio a seguire quel filo. Potrebbe esserci di più in quel vecchio che zoppica con le stampelle di quanto sembri.


6
Non dimenticare la metaprogrammazione dei modelli in C ++. La capacità di eseguire espressioni e prendere decisioni in fase di compilazione e di compilare staticamente i risultati nell'eseguibile finale.
Remy Lebeau

1
Sono rimasto scioccato in order to put technical barriers between us and our competitorse questo è corretto.
Evan Hu,

4
I programmi che manipolano se stessi sono un sottoinsieme di tutti i metaprogrammi. La metaprogrammazione in generale significa solo programmi che manipolano programmi.
JD

55

Ottima domanda. Mi dispiace molto vedere che nessuna delle risposte attualmente risponde correttamente alla tua domanda. Forse posso aiutare ...

La definizione di metaprogrammazione è davvero molto semplice: significa programmi che manipolano programmi.

La tua risposta accettata dice programmi che manipolano se stessi. Quelli sono davvero metaprogrammi ma sono un sottoinsieme di tutti i metaprogrammi.

Tutti:

  • parser
  • Lingue specifiche del dominio (DSL)
  • Linguaggi specifici del dominio incorporato (EDSL)
  • I compilatori
  • interpreti
  • Riscrittori a termine
  • Dimostratori di teoremi

sono metaprogrammi. Quindi il compilatore GCC è un metaprogramma, l' interprete CPython è un metaprogramma, il sistema di computer algebra di Mathematica è un metaprogramma, il prover del teorema di Coq è un metaprogramma e così via.

Altre risposte hanno affermato che i metaprogrammi sono programmi che generano altri programmi. Quelli sono davvero metaprogrammi ma, ancora una volta, sono un sottoinsieme di tutti i metaprogrammi. La libreria Fastest Fourier Transform in the West (FFTW) è un esempio di tale metaprogramma. Il codice sorgente è scritto principalmente in OCaml e genera bit di codice C (chiamati codelets) che vengono combinati per creare routine Fast Fourier Transform ad alte prestazioni ottimizzate per macchine specifiche. Quella libreria viene effettivamente utilizzata per fornire le routine FFT in Matlab. Le persone hanno scritto programmi per generare metodi numerici per decenni, sin dai primi giorni di FORTRAN .

Il primo linguaggio di programmazione che ha integrato il supporto per la metaprogrammazione è stato il linguaggio LISt Processor (LISP) alla fine degli anni '50. LISP 1.5 includeva una serie di funzionalità che rendevano più facile la metaprogrammazione. In primo luogo, il tipo di dati principale di LISP è costituito da elenchi annidati, ad esempio alberi simili (a (b c) d), il che significa che qualsiasi codice LISP può essere espresso in modo nativo come una struttura di dati. Questo è noto come omoiconicità. In secondo luogo, il codice LISP può essere convertito facilmente in dati utilizzando QUOTE. Ad esempio, (+ 1 2 3)aggiunge 1 + 2 + 3 e (QUOTE (+ 1 2 3))crea un'espressione che aggiunge 1 + 2 + 3 quando viene valutata. In terzo luogo, LISP ha fornito un valutatore meta-circolare che consente di utilizzare l'interprete o il compilatore host per valutare il codice LISP in fase di esecuzione, incluso il codice LISP generato in fase di esecuzione. I discendenti di LISP includono Scheme e Clojure. In tutti questi linguaggi la metaprogrammazione è più comunemente vista sotto forma di programmi che si modificano, tipicamente utilizzando macro.

Negli anni '70, Robin Milner ha sviluppato un MetaLanguage (ML) che si è evoluto nella famiglia ML di linguaggi di programmazione che include Standard ML e OCaml e ha fortemente influenzato Haskell e F # . Queste lingue rendono facile esprimere altre lingue. In questi linguaggi i metaprogrammi sono più comunemente visti sotto forma di lexer, parser, interpreti e compilatori.

Nel 1994, Erwin Unruh scoprì che il sistema di template C ++ era completo di Turing e poteva essere utilizzato per eseguire programmi arbitrari in fase di compilazione . La metaprogrammazione del modello C ++ ha portato la metaprogrammazione alle masse non lavate che (ab) la utilizzavano per molte cose diverse, inclusa la generazione di metodi numerici nella libreria Blitz ++ .


33

Beh, la metaprogrammazione è solo programmazione, ma fondamentalmente è "scrivere codice che scrive codice" .

La capacità di cui parli, quando un programma può osservare e modificare la propria struttura e comportamento è chiamata riflessione ed è un tipo di metaprogrammazione.

I linguaggi tipizzati dinamicamente hanno potenti funzionalità di riflessione in fase di esecuzione, rese possibili dalla natura interpretata di questi linguaggi ...

I linguaggi tipizzati statici hanno anche potenti tecniche di metaprogrammazione, ad esempio la metaprogrammazione del modello C ++ ...


14

Questa è solo la mia opinione personale, che è probabilmente la definizione più liberale di metaprogrammazione.

Penso che includa:

  1. Compilare la generazione del codice o la generazione del codice Runtime (o entrambi)
  2. Pensiero orientato agli aspetti o programmazione orientata agli aspetti
  3. Pensiero ASCIUTTO

Penso che tu possa arrivarci usando uno di questi e in combinazione:

  1. Riflessione
  2. DSL (lingue specifiche del dominio)
  3. Attributi (.NET) o Annotazioni (Java)
  4. Generics (.NET / Java)
  5. Modelli (C ++)
  6. method_missing (Ruby)
  7. chiusure / funzioni / delegati di prima classe
  8. AOP - Programmazione orientata agli aspetti

risposta molto concisa e premurosa. mi ha dato un buon menu di cose su cui indagare. grazie!
swyx

6

La metaprogrammazione sta scrivendo un programma che emette un altro programma. Questo è qualcosa in cui linguaggi come il Lisp sono davvero bravi. È molto più facile farlo in un linguaggio che supporta le macro reali (non le macro C ++, ma piuttosto quelle che possono manipolare il codice che producono) come Ruby, Lisp, Scheme, ecc. Che in un linguaggio come Java.

Un'implementazione consiste nel creare un "linguaggio specifico del dominio" che è un modo per migliorare un linguaggio di programmazione per eseguire un'attività specifica. Può essere incredibilmente potente se fatto correttamente. Ruby on Rails è un buon esempio di questo tipo di programmazione.

Se ti interessa esplorare questo metodo, dai un'occhiata a Struttura e interpretazione dei programmi per computer, uno dei libri fondamentali che trattano l'argomento.


5

La metaprogrammazione è la scrittura di programmi per computer che scrivono o manipolano altri programmi (o se stessi) come dati, o che fanno parte del lavoro in fase di esecuzione che altrimenti verrebbe svolto in fase di compilazione. In molti casi, ciò consente ai programmatori di fare di più nella stessa quantità di tempo che impiegherebbero per scrivere tutto il codice manualmente, oppure offre ai programmi una maggiore flessibilità per gestire in modo efficiente nuove situazioni senza ricompilazione. ( Fonte .)

Fondamentalmente, sta scrivendo codice che genera più codice, che viene eseguito per raggiungere un obiettivo. Questo di solito viene fatto all'interno della stessa lingua (utilizzando javascript per creare una stringa javascript, quindi eval) o per emettere un'altra lingua (utilizzando .NET per creare un file batch di Windows).


4

wikipedia ha un bell'articolo sull'argomento. Non è necessario apportare modifiche al runtime affinché qualcosa si qualifichi come metaprogrammazione. Ad esempio, molte persone utilizzano modelli C ++ per eseguire la metaprogrammazione in fase di compilazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.