Wie man den Scala-Compiler erweitert

Scala Macros

Arno Haase


Scala Macros sind Scala-Code, der schon während des Kompilierens ausgeführt wird. Sie können Codeteile als Parameter erhalten und liefern Code zurück. Man kann mit ihnen also Code verändern oder neu erzeugen [1], [2]. Das Besondere an Scala Macros (im Gegensatz z. B. zu C-Macros oder C++-Templates) ist, dass sie in Scala geschrieben sind. Man hat also beim Programmieren von Macros den vollen Sprachumfang von Scala, IDE-Unterstützung, man kann sie Unit-testen etc. Trotzdem vorab ein Wort zur Vorsicht: Macros sind nicht einfach. Sie sind extrem nützlich, und es gibt sehr gute Toolunterstützung. Aber nicht triviale Macros kommen schnell mit dem Syntaxbaum des Scala-Compilers in Berührung. Das ist zwar auch kein Hexenwerk und außerdem gut dokumentiert, aber es ist definitiv weniger handlich, als normale Funktionen zu schreiben.

Warum überhaupt Macros?Macros, oder überhaupt das Generieren von Code, sind ein kontroverses Thema. #defines in C oder Templates in C++ erfreuen sich großer Beliebtheit, werden aber auch teilweise als Quelle überflüssiger Komplexität kritisiert. In Java wurde bewusst auf ein solches Feature verzichtet, um diese Tücken zu vermeiden. Warum hat Scala jetzt also Macros bzw. warum sollte man sie verwenden?Zunächst einmal gibt es Dinge, die man nur mit Macros machen kann: lokale Variablen auswerten, die aktuelle Quelltextposition einbeziehen etc. Viele andere Dinge kann man im Prinzip auch mit Interpretern erledigen (auch wenn sie oft nicht so genannt werden). So ist z. B. String.format letztlich ein Interpreter, der den Format-String zur Laufzeit parst und auswertet. Genauso die RegEx-Implementierung. In der Java-Kultur ist es üblich, zur Laufzeit per Reflection Informationen zu sammeln und auszuwerten, z. B. Constraints aus Annotationen. Es gibt eine Fülle an Beispielen für solche Auswertungen zur Laufzeit.All diese Dinge funktionieren. Sogar gut. Aber sie arbeiten ohne IDE-Unterstützung und werden nicht vom Compiler auf ihre Richtigkeit überprüft. Eine Implementierung mit Macros hätte diese Dinge automatisch. Außerdem erzeugen Macros echten Bytecode, der dann auch von Hotspot optimiert wird.Kurzum, Macros nutzen das Typsystem und den Compiler, um Programmierfehler frühzeitig zu melden, und erzeugen echten Bytecode. Sie sind sicher nicht die Lösung für jedes Problem, aber diese Vorteile sind nicht von der Hand zu weisen.

Ein erstes Macro

Aber das soll uns nicht abschrecken – ich bin von Mac­ros und ihren Fähigkeiten begeistert, und viele Di...

Wie man den Scala-Compiler erweitert

Scala Macros

Arno Haase


Scala Macros sind Scala-Code, der schon während des Kompilierens ausgeführt wird. Sie können Codeteile als Parameter erhalten und liefern Code zurück. Man kann mit ihnen also Code verändern oder neu erzeugen [1], [2]. Das Besondere an Scala Macros (im Gegensatz z. B. zu C-Macros oder C++-Templates) ist, dass sie in Scala geschrieben sind. Man hat also beim Programmieren von Macros den vollen Sprachumfang von Scala, IDE-Unterstützung, man kann sie Unit-testen etc. Trotzdem vorab ein Wort zur Vorsicht: Macros sind nicht einfach. Sie sind extrem nützlich, und es gibt sehr gute Toolunterstützung. Aber nicht triviale Macros kommen schnell mit dem Syntaxbaum des Scala-Compilers in Berührung. Das ist zwar auch kein Hexenwerk und außerdem gut dokumentiert, aber es ist definitiv weniger handlich, als normale Funktionen zu schreiben.

Warum überhaupt Macros?Macros, oder überhaupt das Generieren von Code, sind ein kontroverses Thema. #defines in C oder Templates in C++ erfreuen sich großer Beliebtheit, werden aber auch teilweise als Quelle überflüssiger Komplexität kritisiert. In Java wurde bewusst auf ein solches Feature verzichtet, um diese Tücken zu vermeiden. Warum hat Scala jetzt also Macros bzw. warum sollte man sie verwenden?Zunächst einmal gibt es Dinge, die man nur mit Macros machen kann: lokale Variablen auswerten, die aktuelle Quelltextposition einbeziehen etc. Viele andere Dinge kann man im Prinzip auch mit Interpretern erledigen (auch wenn sie oft nicht so genannt werden). So ist z. B. String.format letztlich ein Interpreter, der den Format-String zur Laufzeit parst und auswertet. Genauso die RegEx-Implementierung. In der Java-Kultur ist es üblich, zur Laufzeit per Reflection Informationen zu sammeln und auszuwerten, z. B. Constraints aus Annotationen. Es gibt eine Fülle an Beispielen für solche Auswertungen zur Laufzeit.All diese Dinge funktionieren. Sogar gut. Aber sie arbeiten ohne IDE-Unterstützung und werden nicht vom Compiler auf ihre Richtigkeit überprüft. Eine Implementierung mit Macros hätte diese Dinge automatisch. Außerdem erzeugen Macros echten Bytecode, der dann auch von Hotspot optimiert wird.Kurzum, Macros nutzen das Typsystem und den Compiler, um Programmierfehler frühzeitig zu melden, und erzeugen echten Bytecode. Sie sind sicher nicht die Lösung für jedes Problem, aber diese Vorteile sind nicht von der Hand zu weisen.

Ein erstes Macro

Aber das soll uns nicht abschrecken – ich bin von Mac­ros und ihren Fähigkeiten begeistert, und viele Di...

Neugierig geworden?


    
Loading...

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang