EMZETT.
Login

Makro (Metaprogrammierung)

Kurz: Ein Makro ist Code, der beim Übersetzen anderen Code erzeugt oder umschreibt. Es erweitert die Sprache selbst und spart Wiederholungen.

Genauer: Es gibt einfache Textersetzung (C-Präprozessor: #define) und mächtige Syntax-Makros, die mit dem Syntaxbaum arbeiten (Lisp, Racket, Rust, Nim, Elixir, Julia). Letztere sind hygienisch, wenn Namen im Makro nicht mit Namen des Aufrufers kollidieren.

Im Detail

#define QUADRAT(x) ((x) * (x))       // Textersetzung; Klammern sind Pflicht!
int a = QUADRAT(3 + 1);              // ((3 + 1) * (3 + 1)) = 16
(defmacro wiederhole (n &body rumpf)
  `(dotimes (i ,n) ,@rumpf))
(wiederhole 3 (print "Hallo"))
macro_rules! maximum {
    ($a:expr) => ($a);
    ($a:expr, $($rest:expr),+) => {{ let r = maximum!($($rest),+); if $a > r { $a } else { r } }};
}
println!("{}", maximum!(3, 9, 4));   // 9

Wofür?

  • Neue Kontrollstrukturen (unless, with-open-file, try-with-resources)
  • Fachsprachen (DSLs), zum Beispiel für Abfragen oder Tests
  • Code-Erzeugung aus Daten (Serialisierung, Parser)
  • Bedingte Übersetzung (#ifdef DEBUG)

Risiken

Textmakros sind fehleranfällig (Mehrfachauswertung von Argumenten: QUADRAT(i++)), und viele Makros machen Code schwer zu lesen. Faustregel: erst Funktion, dann Makro – nur wenn sich etwas ohne Makro nicht ausdrücken lässt.

Ausführliche Makro-Kapitel enthalten die Kurse Common Lisp, Racket, Scheme und Nim. Zur Laufzeit arbeitet dagegen Reflection.

Siehe auch: Reflection, Annotationen, Compiler, Lambda-Ausdruck