Was genau ist Metaprogrammierung?

128

Ich habe einen Artikel über TheServerSide gelesen Ployglot-Programmierung auf der Java-Plattform gelesen . Einige Kommentare im Artikel beziehen sich auf Metaprogrammierung als die Fähigkeit, Code zu generieren (möglicherweise im laufenden Betrieb).

Ist Metaprogrammierung die Fähigkeit, Code im laufenden Betrieb zu generieren, oder ist es die Fähigkeit, Methoden und Attribute zur Laufzeit in vorhandene Objekte einzufügen (wie es einige dynamische Sprachen wie Python, Ruby und Groovy zulassen).

Parag
quelle
7
Diese Antwort könnte Sie interessieren stackackflow.com/questions/2565572/…
ewernli
@ewernli: Diese Antwort ist tatsächlich besser als jede der Antworten hier!
JD

Antworten:

100

Metaprogrammierung bezieht sich auf eine Vielzahl von Möglichkeiten, wie ein Programm sich selbst kennt oder sich selbst manipulieren kann.

In Sprachen wie C # ist Reflexion eine Form der Metaprogrammierung, da das Programm Informationen über sich selbst untersuchen kann. Zum Beispiel eine Liste aller Eigenschaften eines Objekts zurückgeben.

In Sprachen wie ActionScript können Sie Funktionen zur Laufzeit auswerten, um neue Programme wie eval ("x" + i) zu erstellen. DoSomething () würde ein Objekt namens x1 beeinflussen, wenn i 1 ist, und x2, wenn i 2 ist.

Schließlich ist eine andere übliche Form der Metaprogrammierung, wenn sich das Programm auf nicht triviale Weise ändern kann. LISP ist dafür bekannt und hat sich vor etwa einem Jahrzehnt für Paul Graham eingesetzt. Ich muss einige seiner spezifischen Aufsätze nachschlagen. Die Idee ist jedoch, dass das Programm einen anderen Teil des Programms basierend auf seinem Status ändern würde. Dies ermöglicht ein Maß an Flexibilität, um Entscheidungen zur Laufzeit zu treffen, das in den meisten gängigen Sprachen heutzutage sehr schwierig ist.

Es ist auch erwähnenswert, dass in den guten alten Tagen der Programmierung in gerader Montage Programme, die sich zur Laufzeit selbst änderten, notwendig und sehr alltäglich waren.

Aus Paul Grahams Essay "Was Lisp anders gemacht hat" :

Viele Sprachen haben so etwas wie ein Makro. Aber Lisp-Makros sind einzigartig. Und ob Sie es glauben oder nicht, was sie tun, hängt mit den Klammern zusammen. Die Designer von Lisp haben nicht alle diese Klammern in die Sprache gesetzt, nur um anders zu sein. Für den Blub-Programmierer sieht Lisp-Code seltsam aus. Aber diese Klammern gibt es aus einem Grund. Sie sind der äußere Beweis für einen grundlegenden Unterschied zwischen Lisp und anderen Sprachen.

Lisp-Code besteht aus Lisp-Datenobjekten. Und nicht in dem trivialen Sinne, dass die Quelldateien Zeichen enthalten und Zeichenfolgen einer der von der Sprache unterstützten Datentypen sind. Lisp-Code besteht nach dem Lesen durch den Parser aus Datenstrukturen, die Sie durchlaufen können.

Wenn Sie verstehen, wie Compiler funktionieren, ist das, was wirklich vor sich geht, nicht so sehr, dass Lisp eine seltsame Syntax hat, als dass Lisp keine Syntax hat. Sie schreiben Programme in die Analysebäume, die im Compiler generiert werden, wenn andere Sprachen analysiert werden. Diese Analysebäume sind jedoch für Ihre Programme vollständig zugänglich. Sie können Programme schreiben, die sie manipulieren. In Lisp werden diese Programme als Makros bezeichnet. Sie sind Programme, die Programme schreiben.

Programme, die Programme schreiben? Wann würden Sie das jemals tun wollen? Nicht sehr oft, wenn man an Cobol denkt. Die ganze Zeit, wenn Sie in Lisp denken. Hier wäre es praktisch, wenn ich ein Beispiel für ein leistungsfähiges Makro geben und dort sagen könnte! wie wär es damit? Aber wenn ich es tun würde, würde es für jemanden, der Lisp nicht kannte, nur wie Kauderwelsch aussehen. Hier ist kein Platz, um alles zu erklären, was Sie wissen müssen, um zu verstehen, was es bedeutet. In Ansi Common Lisp ich versucht, die Dinge so schnell wie möglich voranzutreiben, und trotzdem bin ich erst auf Seite 160 zu Makros gekommen.

Aber ich denke, ich kann eine Art Argument vorbringen, das überzeugend sein könnte. Der Quellcode des Viaweb-Editors bestand wahrscheinlich aus etwa 20-25% Makros. Makros sind schwieriger zu schreiben als normale Lisp-Funktionen, und es wird als schlechter Stil angesehen, sie zu verwenden, wenn sie nicht erforderlich sind. Jedes Makro in diesem Code ist also da, weil es sein muss. Das bedeutet, dass mindestens 20-25% des Codes in diesem Programm Dinge tun, die Sie in keiner anderen Sprache einfach tun können. So skeptisch der Blub-Programmierer auch gegenüber meinen Behauptungen über die mysteriösen Kräfte von Lisp sein mag, dies sollte ihn neugierig machen. Wir haben diesen Code nicht zu unserer eigenen Unterhaltung geschrieben. Wir waren ein winziges Startup, das so hart wie möglich programmierte, um technische Barrieren zwischen uns und unseren Konkurrenten zu schaffen.

Eine verdächtige Person könnte sich fragen, ob hier ein Zusammenhang besteht. Ein großer Teil unseres Codes hat Dinge getan, die in anderen Sprachen sehr schwer zu tun sind. Die resultierende Software hat Dinge getan, die die Software unserer Konkurrenten nicht konnte. Vielleicht gab es irgendeine Verbindung. Ich ermutige Sie, diesem Thread zu folgen. Dieser alte Mann kann mehr auf seinen Krücken humpeln, als man denkt.

DavGarcia
quelle
6
Vergessen Sie nicht die Metaprogrammierung von Vorlagen in C ++. Die Fähigkeit, Ausdrücke auszuführen und Entscheidungen zur Kompilierungszeit zu treffen und die Ergebnisse statisch in die endgültige ausführbare Datei zu kompilieren.
Remy Lebeau
1
Ich war schockiert in order to put technical barriers between us and our competitorsund das ist Tamade richtig.
Evan Hu
4
Programme, die sich selbst manipulieren, sind eine Teilmenge aller Metaprogramme. Metaprogrammierung im Allgemeinen bedeutet nur Programme, die Programme manipulieren.
JD
55

Gute Frage. Es tut mir sehr leid zu sehen, dass keine der Antworten Ihre Frage derzeit wirklich richtig beantwortet. Vielleicht kann ich helfen ...

Die Definition der Metaprogrammierung ist wirklich recht einfach: Es handelt sich um Programme, die Programme manipulieren.

Ihre akzeptierte Antwort lautet Programme, die sich selbst manipulieren. Das sind zwar Metaprogramme, aber sie sind eine Teilmenge aller Metaprogramme.

Alles:

  • Parser
  • Domänenspezifische Sprachen (DSLs)
  • Eingebettete domänenspezifische Sprachen (EDSLs)
  • Compiler
  • Dolmetscher
  • Term Rewriter
  • Theorembeweiser

sind Metaprogramme. Der GCC-Compiler ist also ein Metaprogramm, der CPython-Interpreter ist ein Metaprogramm, das Mathematica-Computeralgebrasystem ist ein Metaprogramm, der Coq-Theorembeweiser ist ein Metaprogramm und so weiter.

Andere Antworten haben behauptet, dass Metaprogramme Programme sind, die andere Programme erzeugen. Dies sind zwar Metaprogramme, aber sie sind wiederum eine Teilmenge aller Metaprogramme. Die FFTW-Bibliothek ( Fastest Fourier Transform in the West ) ist ein Beispiel für ein solches Metaprogramm. Der Quellcode wird hauptsächlich in OCaml geschrieben und generiert C-Code-Bits (Codelets genannt), die kombiniert werden, um leistungsstarke Fast Fourier Transform- Routinen zu erstellen, die für bestimmte Maschinen optimiert sind. Diese Bibliothek wird tatsächlich verwendet, um die FFT-Routinen in Matlab bereitzustellen. Seit den Anfängen von FORTRAN schreiben Menschen seit Jahrzehnten Programme, um numerische Methoden zu generieren .

Die erste Programmiersprache, die die Unterstützung für Metaprogrammierung integrierte, war Ende der 1950er Jahre die Sprache LISt Processor (LISP). LISP 1.5 enthielt eine Reihe von Funktionen, die die Metaprogrammierung vereinfachten. Erstens besteht der Kerndatentyp von LISP aus verschachtelten Listen, dh Bäumen wie (a (b c) d), was bedeutet, dass jeder LISP-Code nativ als Datenstruktur ausgedrückt werden kann. Dies ist als Homoikonizität bekannt. Zweitens kann LISP-Code mit QUOTE einfach in Daten konvertiert werden. Fügt beispielsweise (+ 1 2 3)1 + 2 + 3 hinzu und (QUOTE (+ 1 2 3))erstellt einen Ausdruck, der bei der Auswertung 1 + 2 + 3 hinzufügt. Drittens stellte LISP einen Meta-Circular-Evaluator zur Verfügung, mit dem Sie den Host-Interpreter oder -Compiler verwenden können, um LISP-Code zur Laufzeit zu bewerten, einschließlich zur Laufzeit generiertem LISP-Code. Zu den Nachkommen von LISP gehören Scheme und Clojure. In all diesen Sprachen wird Metaprogrammierung am häufigsten in Form von Programmen gesehen, die sich selbst ändern, typischerweise unter Verwendung von Makros.

In den 1970er Jahren entwickelte Robin Milner eine MetaLanguage (ML), die sich zur ML-Familie von Programmiersprachen entwickelte, die Standard ML und OCaml umfasst und Haskell und F # stark beeinflusst . Diese Sprachen machen es einfach, andere Sprachen auszudrücken. In diesen Sprachen werden Metaprogramme am häufigsten in Form von Lexern, Parsern, Interpreten und Compilern gesehen.

1994 entdeckte Erwin Unruh, dass das C ++ - Vorlagensystem Turing vollständig war und zur Ausführung beliebiger Programme zur Kompilierungszeit verwendet werden konnte . Die Metaprogrammierung von C ++ - Vorlagen brachte die Metaprogrammierung zu den ungewaschenen Massen, die sie (ab) für viele verschiedene Zwecke verwendeten, einschließlich der Generierung numerischer Methoden in der Blitz ++ - Bibliothek .

JD
quelle
33

Nun, Metaprogrammierung ist nur Programmieren, aber es ist im Grunde "Code schreiben, der Code schreibt" .

Die Fähigkeit, die Sie erwähnen, wenn ein Programm seine eigene Struktur und sein eigenes Verhalten beobachten und ändern kann, wird als Reflexion bezeichnet und ist eine Art Metaprogrammierung.

Dynamisch typisierte Sprachen verfügen über leistungsstarke Funktionen zur Laufzeitreflexion, die durch die Interpretation dieser Sprachen ermöglicht werden ...

Statisch typisierte Sprachen verfügen auch über leistungsstarke Metaprogrammiertechniken, beispielsweise die C ++ - Vorlagen-Metaprogrammierung ...

CMS
quelle
14

Dies ist nur meine persönliche Meinung, die wahrscheinlich die liberalste Definition von Metaprogrammierung ist.

Ich denke, es beinhaltet:

  1. Kompilieren Sie die Codegenerierung oder die Laufzeitcodegenerierung (oder beides).
  2. Aspektorientiertes Denken oder aspektorientiertes Programmieren
  3. TROCKENES Denken

Ich denke, Sie können dorthin gelangen, indem Sie eines davon und in Kombination verwenden:

  1. Reflexion
  2. DSLs (Domain Specific Languages)
  3. Attribute (.NET) oder Anmerkungen (Java)
  4. Generika (.NET / Java)
  5. Vorlagen (C ++)
  6. method_missing (Ruby)
  7. Schließungen / erstklassige Funktionen / Delegierte
  8. AOP - Aspektorientierte Programmierung
BuddyJoe
quelle
sehr prägnante und nachdenkliche Antwort. gab mir eine gute Auswahl an Dingen zu untersuchen. Danke!
Swyx
6

Metaprogrammierung schreibt ein Programm, das ein anderes Programm ausgibt. Das ist etwas, was Sprachen wie Lisp wirklich gut können. In einer Sprache, die echte Makros unterstützt (nicht C ++ - Makros, sondern solche, die den von ihnen ausgegebenen Code manipulieren können), wie Ruby, Lisp, Scheme usw., ist dies viel einfacher als in einer Sprache wie Java.

Eine Implementierung besteht darin, eine "domänenspezifische Sprache" zu erstellen, mit der eine Programmiersprache erweitert werden kann, um eine bestimmte Aufgabe zu erfüllen. Es kann unglaublich mächtig sein, wenn es richtig gemacht wird. Ruby on Rails ist ein gutes Beispiel für diese Art der Programmierung.

Wenn Sie sich für diese Methode interessieren, lesen Sie die Struktur und Interpretation von Computerprogrammen , eines der wichtigsten Bücher zu diesem Thema.

Steve Rowe
quelle
5

Metaprogrammierung ist das Schreiben von Computerprogrammen, die andere Programme (oder sich selbst) als Daten schreiben oder bearbeiten oder die zur Laufzeit einen Teil der Arbeit erledigen, die sonst zur Kompilierungszeit ausgeführt würde. In vielen Fällen können Programmierer auf diese Weise mehr in der gleichen Zeit erledigen, die sie zum manuellen Schreiben des gesamten Codes benötigen würden, oder Programme erhalten mehr Flexibilität, um neue Situationen ohne Neukompilierung effizient zu handhaben. ( Quelle .)

Im Grunde ist es das Schreiben von Code, der mehr Code ausgibt, der ausgeführt wird, um ein bestimmtes Ziel zu erreichen. Dies erfolgt normalerweise entweder in derselben Sprache (mit Javascript, um eine Javascript-Zeichenfolge zu erstellen, evaloder dann ) oder um eine andere Sprache auszugeben (mit .NET, um eine Windows-Batchdatei zu erstellen).

Gefährdete Masse
quelle
4

Wikipedia hat einen schönen Artikel zum Thema. Man muss keine Laufzeitänderungen vornehmen, um etwas als Metaprogrammierung zu qualifizieren. Beispielsweise verwenden viele Benutzer C ++ - Vorlagen, um zur Kompilierungszeit Metaprogrammierungen durchzuführen.

Herr Fooz
quelle