← Alle Beitrage

Engineering-Philosophie: Roberto Ierusalimschy

Roberto Ierusalimschy, Schöpfer von Lua

Die wichtigsten Erkenntnisse

  • Er entwarf die Skriptsprache, die in einem enormen Teil der Software steckt, die Sie täglich benutzen. Roberto Ierusalimschy leitete den Entwurf von Lua, das 1993 im Tecgraf-Labor der PUC-Rio gemeinsam mit Luiz Henrique de Figueiredo und Waldemar Celes entstand. Es steuert die Spiellogik in World of Warcraft, Roblox (über dessen Luau-Dialekt), Dota 2 und Garry’s Mod, skriptet Redis und nginx (über OpenResty), treibt Adobe Lightroom und Wireshark an und ist in Geräte eingebettet, bis hinunter zu Robotern ohne jegliches Betriebssystem darunter.127
  • Mechanismen statt Vorgaben. Luas prägende Entscheidung ist eine Verweigerung – es liefert kein Klassensystem mit, kein Objektmodell, kein Paradigma. Es gibt Ihnen einige wenige, mächtige, allgemeine Mechanismen (Tabellen, Metatabellen, Coroutinen) und überlässt Ihnen den Aufbau Ihrer eigenen Abstraktionen darauf. „Lua zwingt dem Programmierer kein Objekt- oder Klassenmodell auf”, schrieben die Entwickler; stattdessen stellen sie „flexible Mechanismen bereit”, damit Sie jedes Modell bauen können, das zur Anwendung passt.3
  • Kleinheit ist eine Eigenschaft, keine Beschränkung. Die Referenzimplementierung ist winzig und sauber – der Quelltext von Lua 5.1 umfasst rund 17.000 Zeilen C, die gesamte Distribution passt auf eine Diskette, und der fertige Interpreter ist etwa 143 KB groß. Die meisten Skriptsprachen sind um eine Größenordnung umfangreicher; Lua bleibt gerade deshalb klein, weil es zum Einbetten gedacht ist, und Einfachheit ist es, die eine kleine, schnelle Implementierung überhaupt möglich macht.3
  • Portabilität und Einbettbarkeit waren vom ersten Tag an Entwurfsziele. Lua ist in „sauberem C” geschrieben – der Schnittmenge von C und C++ – und „kompiliert auf den meisten Plattformen ohne Anpassung”, von Linux und Windows bis zu Handgeräten und Mikrocontrollern. Eine klar definierte C-API erlaubt es einem Wirtsprogramm, Lua vollständig zu steuern und zu erweitern – genau der Grund, warum die Spielebranche es als Quasi-Standard übernahm.34

Das Prinzip

„Wir wollten Lua nicht in eine objektorientierte Sprache verwandeln, weil wir kein Programmierparadigma für Lua festlegen wollten… Lua zwingt dem Programmierer kein Objekt- oder Klassenmodell auf. Stattdessen… entschieden wir uns, flexible Mechanismen bereitzustellen, die es dem Programmierer erlauben würden, das jeweils zur Anwendung passende Modell selbst zu bauen.” – Roberto Ierusalimschy, Luiz Henrique de Figueiredo und Waldemar Celes, The Evolution of Lua3

Der Entwurf der meisten Sprachen ist die Anhäufung von Vorgaben. Ein Team beschließt, dass Objekte so funktionieren sollen, dass Fehlerbehandlung jenem Muster folgen soll, dass Nebenläufigkeit Threads oder async oder Aktoren bedeutet – und es backt diese Entscheidungen fest in die Sprache ein, sodass jedes darin geschriebene Programm die Wahl erbt. Die Entscheidungen sind meist vernünftig. Das Problem ist, dass es Entscheidungen sind, einmal getroffen, für alle, von Menschen, die Ihre Anwendung gar nicht kennen konnten. Ierusalimschys Instinkt lief in die entgegengesetzte Richtung. Statt für Sie zu entscheiden, gibt Lua Ihnen eine kleine Auswahl allgemeiner Mechanismen an die Hand und tritt zurück, damit Sie genau die Vorgaben bauen können, die Ihr Problem tatsächlich braucht.3

Der deutlichste Fall ist die Objektorientierung. In den frühen 1990er-Jahren, als die objektorientierte Programmierung auf dem Höhepunkt ihres Hypes stand, drängten Benutzer das Lua-Team, Klassen und Vererbung hinzuzufügen. Sie weigerten sich – nicht weil OOP falsch gewesen wäre, sondern weil es falsch war, ein einziges Modell festzulegen für eine Sprache, die in völlig unterschiedliche Anwendungen eingebettet werden sollte. Objekte und Klassen „ließen sich bei Bedarf mit Tabellen umsetzen”, überlegten sie, da eine Tabelle sowohl Daten als auch Methoden aufnehmen kann und Funktionen vollwertige Werte sind.3 Statt eines Objektsystems bauten sie also erweiterbare Semantik – einen Mechanismus, der es Ihnen erlaubt, in das Verhalten von Tabellen einzugreifen – und überließen es den Benutzern, Vererbung, Vorgabewerte, schreibgeschützte Sichten und vollständige Klassenhierarchien selbst zusammenzusetzen. „Erweiterbare Semantik ist zu einem Markenzeichen von Lua geworden”, schrieben sie, und sie haben „ihre Meinung bis heute nicht geändert”.3

Diese Verweigerung ist nur deshalb tragbar, weil drei weitere Grundsätze sie begleiten. Einfachheit – die Sprache bleibt klein genug, dass die Mechanismen verständlich und die Implementierung korrekt sind. Kleinheit als Eigenschaft – die gesamte Referenzimplementierung umfasst rund 17.000 Zeilen sauberen C-Codes, klein genug, dass das Hinzufügen von Lua zu einer Anwendung „diese nicht aufbläht”.3 Und Portabilität – das Schreiben in der Schnittmenge von C und C++ bedeutet, dass derselbe Quelltext überall kompiliert, vom Supercomputer bis zum Sensor.3 Geben Sie den Leuten ein paar scharfe, allgemeine Hebel statt eines Schranks voller vorab entschiedener Knöpfe, und halten Sie das Ganze klein genug, um es überallhin mitzunehmen. Das ist das Prinzip, und alles andere in Lua ist eine Folge davon.

Kontext

Roberto Ierusalimschy wurde am 21. Mai 1960 in Rio de Janeiro geboren, und seine gesamte Laufbahn blieb einer einzigen Institution verbunden – der Päpstlichen Katholischen Universität von Rio de Janeiro (PUC-Rio), wo er 1990 in Informatik promovierte und wo er ordentlicher Professor für Informatik ist. Er absolvierte einen Postdoc an der University of Waterloo und einen Aufenthalt als Gastprofessor in Stanford, doch die PUC-Rio ist sein Zuhause, und die Lua-Geschichte ist von einem bestimmten Labor dort untrennbar.5

Dieses Labor ist Tecgraf, die Computer Graphics Technology Group, 1987 gegründet, um Softwarewerkzeuge für industrielle Kunden zu bauen – einer der größten davon war und ist bis heute der brasilianische Ölkonzern Petrobras.3 Der Ursprung von Lua ist zum Teil eine Geschichte über brasilianische Handelspolitik. Von 1977 bis 1992 hielt Brasilien eine Politik starker Handelsschranken aufrecht – einen „Marktvorbehalt” – für Computerhardware und -software, getragen von der nationalistischen Überzeugung, das Land könne und solle seine eigene bauen. In diesem Klima „konnten es sich Tecgrafs Kunden weder politisch noch finanziell leisten, maßgeschneiderte Software aus dem Ausland zu kaufen”. Der Kauf ausländischer Werkzeuge bedeutete einen „komplizierten bürokratischen Prozess, um nachzuweisen, dass ihr Bedarf nicht von brasilianischen Unternehmen gedeckt werden konnte”. Diese Beschränkungen, kombiniert mit Brasiliens geografischer Abgeschiedenheit von anderen Forschungszentren, „brachten Tecgraf dazu, die grundlegenden Werkzeuge, die es brauchte, von Grund auf selbst zu bauen”.3 Lua ist nach dem eigenen Bekunden seiner Entwickler „die einzige Sprache, die in einem Entwicklungsland geschaffen wurde und globale Bedeutung erlangt hat”.3

Vor Lua gab es zwei kleine Sprachen, beide für Petrobras gebaut. DEL – „data-entry language” – erzeugte grafische Eingabemasken, sodass Ingenieure die Eingaben für Simulatoren durch Klicken auf ein Diagramm vornehmen konnten, statt Zahlenkolonnen zu bearbeiten.3 SOL – „Simple Object Language” – war eine Konfigurationssprache für einen Berichtsgenerator, mit einer von BibTeX beeinflussten Syntax zur Typdeklaration.3 Anfang 1993 waren beide über ihren ursprünglichen Zweck hinausgewachsen; die Benutzer von DEL wollten echte Ablaufsteuerung, und SOL brauchte prozedurale Mächtigkeit. Mitte 1993 kamen Ierusalimschy, de Figueiredo und Celes zu dem Schluss, dass die beiden durch eine einzige, mächtigere Sprache ersetzt werden könnten – und das Lua-Team war geboren.3 Der Name ist ein kleiner Scherz, der hängen blieb. SOL bedeutet „Sonne” auf Portugiesisch; ein Freund bei Tecgraf, Carlos Henrique Levy, schlug vor, den Nachfolger ‚Lua’ – „Mond” auf Portugiesisch zu nennen.3 Bis Juli 1993 hatte Waldemar Celes die erste Implementierung fertiggestellt, gebaut als Kursprojekt unter Ierusalimschys Betreuung und dem Extreme-Programming-Grundsatz „das Einfachste, was möglicherweise funktionieren könnte” folgend.3

Die Arbeit

Tabellen und Metatabellen: eine Datenstruktur, ein Mechanismus

Beginnen Sie mit der Tabelle, denn sie ist die ganze Sprache im Kleinen. Lua bietet einen einzigen Mechanismus zur Datenstrukturierung – die Tabelle, sein Begriff für ein assoziatives Array – und diese eine Struktur erledigt die Arbeit von Records, Arrays, Mengen, Listen, Modulen und Objekten.3 „Obwohl die meisten Skriptsprachen assoziative Arrays anbieten”, merken die Entwickler an, „spielen assoziative Arrays in keiner anderen Sprache eine derart zentrale Rolle”.3 Ein Record ist eine Tabelle, die über Feldnamen indiziert wird; ein Array ist eine Tabelle, die über ganze Zahlen indiziert wird; ein Objekt ist eine Tabelle, die zufällig sowohl Daten als auch Methoden enthält. Ein Mechanismus, viele Verwendungen – genau die Wette „Mechanismen statt Vorgaben”, angewandt auf Daten.

Der Hebel, der Tabellen programmierbar macht, ist die Metatabelle. Normalerweise liefert das Nachschlagen eines Schlüssels, den die Tabelle nicht besitzt, nil zurück. Aber Sie können einer Tabelle eine Metatabelle geben – eine zweite Tabelle, die beschreibt, wie sich die erste in ungewöhnlichen Situationen verhalten soll. Der wichtigste Eintrag ist __index: Wenn ein Nachschlagen ins Leere läuft, befragt Lua das __index der Metatabelle, das auf eine weitere Tabelle verweisen kann, in der als Nächstes gesucht wird. Verketten Sie diese, und Sie haben Vererbung, gebaut aus nichts als Tabellen und einer einzigen Umleitung. Derselbe Mechanismus liefert Ihnen unter anderen Metamethoden Operatorüberladung, Vorgabewerte, schreibgeschützte Stellvertreter und verzögert berechnete Felder. Nichts davon ist ein Sprachmerkmal im üblichen Sinne – es ist alles ein einziger Mechanismus, in unterschiedlichen Formen verwendet.3

Dieser Mechanismus kam nicht in einem Stück – seine Entwicklung ist selbst eine Lektion in Zurückhaltung. Er begann in Lua 2.1 (1995) als „fallbacks”: Haken, die Lua aufrief, wenn eine Operation auf die „falsche” Art von Wert angewandt wurde, sodass der Programmierer entscheiden konnte, was als Nächstes geschah.3 Der Tabellenindex-Fallback ließ userdata und andere Werte „sich wie Tabellen verhalten” und unterstützte „viele Formen der Vererbung (durch Delegation)”.3 Fallbacks waren global – ein Haken pro Ereignis – was sie über Bibliotheken hinweg schwer teilbar machte, also ersetzte Lua 3.0 (1997) sie durch typgebundene „tag methods”, und Lua 5.0 (2003) vereinheitlichte alles zu Metatabellen und Metamethoden, der Form, die Lua heute verwendet. (Der Begriff „Metatabelle” wurde 2001 von Rici Lake vorgeschlagen.)3 Jeder Schritt verallgemeinerte den Mechanismus, statt neue Merkmale aufzuhäufen – derselbe Instinkt, der die Sprache ein Klassensystem weiterhin verweigern ließ.

Einbettbarkeit, die C-API und warum Spiele Lua übernahmen

Lua ist eigentlich gar nicht als eigenständige Sprache gedacht. Die Entwickler nennen es eine „erweiterbare Erweiterungssprache” – eine Erweiterungssprache, weil es eine Wirtsanwendung durch Konfiguration und Skripting erweitert, und erweiterbar, weil es seinerseits mit C-Funktionen erweitert werden kann.3 Das Scharnier ist eine klar definierte C-API, die „vollständige Kommunikation zwischen Lua-Code und externem Code” erlaubt, gebaut um eine saubere Stack-Metapher zum Hin- und Herreichen von Werten zwischen Lua und dem Wirt. Die API lässt Lua nicht nur mit C und C++ zusammenarbeiten, sondern über diese hinweg auch mit Fortran, Java, C# und ganz anderen Sprachen.3

Der Lohn kam mit Spielen, und die Geschichte ist konkret. Im Januar 1997 erzählte Bret Mogilefsky – leitender Programmierer des LucasArts-Adventures Grim Fandango – dem Lua-Team, er habe die selbstgebaute Skriptsprache des Spiels durch Lua ersetzt und „ein gewaltiger Anteil des Spiels sei in Lua geschrieben”.3 Mogilefsky sprach bei einer Gesprächsrunde auf einer Game Developers’ Conference darüber, und von dort „verbreitete sich Lua mündlich unter Spieleentwicklern und wurde zu einer durchaus marktfähigen Fähigkeit in der Spielebranche”.3 Die Passung ist struktureller Natur. Eine Spiel-Engine ist genau die Art von Wirt, die von einer eingebetteten Skriptschicht profitiert – die Schwerstarbeit (Rendering, Physik) bleibt in schnellem C++, während Spiellogik, Quests und Verhalten in kleinen Lua-Skripten leben, die Designer bearbeiten und neu laden können, ohne die Engine neu kompilieren zu müssen. Klein, schnell, portabel und einbettbar war genau das Profil, das ein Spiel brauchte, und Lua war von der ersten Veröffentlichung an dafür gebaut.34

Coroutinen und eine kleine, schnelle Implementierung

Der dritte große Mechanismus ist die Coroutine – und wie OOP ist sie die bewusste Verweigerung einer Vorgabe durch das Team. Über die späten 1990er-Jahre hinweg drängten Benutzer auf Multithreading, und der naheliegende Zug wäre gewesen, das übliche präemptive Threading-Modell mit gemeinsam genutztem Speicher zu übernehmen. Das Lua-Team lehnte ab, aus zwei Gründen: Die Umsetzung präemptiver Threads in C erfordert Primitive, „die nicht Teil von ANSI C sind”, was Luas Portabilität gebrochen hätte, und – grundlegender – „wir glaubten (und glauben noch immer) nicht an das übliche Multithreading-Modell”, in dem „niemand korrekte Programme in einer Sprache schreiben kann, in der ‚a=a+1’ nicht deterministisch ist”.3 Statt Threads lieferten sie also Coroutinen in Lua 5.0 (2003): einen Mechanismus für kooperatives, nicht-präemptives Multitasking, bei dem eine Funktion sich selbst anhalten und später genau dort fortsetzen kann, wo sie aufgehört hat.3 Coroutinen geben Ihnen die Ausdruckskraft der Nebenläufigkeit – Generatoren, kooperative Scheduler, Zustandsmaschinen – ohne den Indeterminismus, der Threads mit gemeinsam genutztem Speicher so schwer richtig hinzubekommen macht. Ein Mechanismus, keine Vorgabe – wieder einmal.

Unter alldem sitzt eine Implementierung, die gerade deshalb schnell ist, weil sie klein ist. Luas virtuelle Maschine war bis Lua 4.0 stapelbasiert; mit Lua 5.0 wurde sie registerbasiert, was dem Codegenerator mehr Spielraum zur Optimierung gab und die Zahl der VM-Instruktionen verringerte, die ein typisches Programm ausführt. Die Entwickler merken an, dass „die virtuelle Maschine von Lua 5.0 die erste registerbasierte virtuelle Maschine mit breiter Verwendung war”.3 Der Speicher wird von einem inkrementellen Garbage Collector verwaltet (eingeführt in Lua 5.1), der seine Arbeit in kleinen Schritten erledigt statt in langen Stop-the-World-Pausen – wichtig für die Echtzeitschleifen eines Spiels.3 Unabhängige Benchmarks reihen Lua unter die schnellsten der interpretierten Skriptsprachen ein, schnell genug, dass nach Angaben der Entwickler „über 40 % von Adobe Lightroom in Lua geschrieben sind”, rund 100.000 Zeilen davon.3

Die Programmiersprache Lua

Luas Reichweite: von World of Warcraft bis zu einem Roboter ohne Betriebssystem

Zählt man all das zusammen, wurde Lua zur unsichtbaren Skriptschicht eines enormen Ausschnitts der Software. Bei den Spielen öffnet World of Warcraft seine gesamte Oberfläche für Lua, damit Spieler Add-ons schreiben können; Roblox baute Luau, einen Lua-Dialekt, als die Sprache, in der Millionen junger Schöpfer das Programmieren lernen; Dota 2, Crysis und Garry’s Mod betten es ebenfalls ein.1 Außerhalb von Spielen führt Redis Lua-Skripte atomar innerhalb der Datenbank aus; nginx programmiert über die OpenResty-Distribution den Webserver selbst mit Lua; Adobe Lightroom und Wireshark sind zu großen Teilen darauf gebaut; Neovim übernahm Lua als vollwertige Konfigurations- und Plugin-Sprache.1 Und weil der Interpreter klein und portabel ist, reicht Lua bis in Hardware hinein, die fast nichts anderes besitzt – die Entwickler berichten von Crazy Ivan, einem RoboCup-Sieger, dessen „Gehirn” Lua „direkt auf einem Motorola-Coldfire-5206e-Prozessor ohne jedes Betriebssystem ausführte; mit anderen Worten, Lua war das Betriebssystem”.7 Eine kleine Sprache, gebaut in einem Labor in Rio unter Handelsbeschränkungen, landete am Ende überall – weil sie fast nichts verlangte und Ihnen die Hebel gab, um den Rest zu bauen.

Die Methode

Liest man DEL, SOL, die Metatabelle, die Coroutinen und dreißig Jahre der Weigerung, die Sprache aufzublähen, im Zusammenhang, kehren dieselben Züge wieder. Ierusalimschys Methode ist weniger ein Slogan als ein Satz dauerhafter Grundsätze.

Liefern Sie Mechanismen, keine Vorgaben. Die prägende Gewohnheit ist, einen allgemeinen Hebel bereitzustellen und die Entscheidung darüber zu verweigern, wie er verwendet werden muss. Kein eingebautes Klassensystem, kein festes Nebenläufigkeitsmodell – nur Tabellen, Metatabellen und Coroutinen, aus denen Sie bauen, was Ihre Anwendung braucht. Die allgemeine Lehre überträgt sich weit über den Sprachentwurf hinaus: Die beständigsten Werkzeuge sind diejenigen, die Fähigkeit verleihen, ohne die Form der Lösung vorzuschreiben. Es ist das Gegenteil von Guido van Rossums „es sollte einen offensichtlichen Weg geben, es zu tun”, und der Gegensatz ist der entscheidende Punkt – beide sind in sich stimmig, und zu wissen, welche Philosophie Ihr Werkzeug verkörpern soll, ist die eigentliche Entscheidung.3

Halten Sie es klein genug, um korrekt zu sein und überallhin mitgenommen werden zu können. Luas Referenzimplementierung umfasst rund 17.000 Zeilen sauberen C-Codes, eine Größenordnung kleiner als andere Skriptsprachen, und diese Kleinheit ist eine bewusste Eigenschaft – sie ist es, die die Sprache einbettbar, portabel und vertrauenswürdig macht. Die Disziplin besteht darin, weiterzukürzen, bis das Entfernen einer weiteren Sache sie zerbricht, was Lua zum Software-Spiegelbild von Sophie Wilsons schonungslosem Minimalismus in ARM macht – auf die tragende Essenz reduzieren und die Effizienz gratis abfallen lassen. Es ist ein minimal lohnenswertes Produkt auf der Ebene einer Sprachlaufzeitumgebung.3

Widerstehen Sie der Funktion, um die Sie gebeten werden, bis Sie den Mechanismus darunter finden. Als Benutzer Objekte verlangten, gab Lua ihnen erweiterbare Semantik; als sie Threads verlangten, gab es ihnen Coroutinen. Jedes Mal lehnte das Team die konkrete Vorgabe ab und lieferte den allgemeineren Mechanismus, der es den Benutzern erlaubte, die Vorgabe selbst zu bauen – und änderte, entscheidend, Jahre später seine Meinung nicht.3 Das ist die Beweisschwelle, angewandt auf Funktionswünsche: Fügen Sie die Sache nicht hinzu, weil danach gefragt wird; finden Sie heraus, welches Problem sie löst und ob ein Mechanismus, den Sie bereits haben, es lösen kann.

Verallgemeinern Sie, häufen Sie nicht an. Die Metatabelle kam nicht in einem Stück – sie wuchs von Fallbacks über Tag-Methoden zu Metamethoden, und jeder Schritt ersetzte den vorherigen Mechanismus durch einen allgemeineren, statt ein neues Merkmal daneben zu schrauben.3 Die Lehre ist, durch Vereinheitlichung zu wachsen, nicht durch Hinzufügung, sodass die Sprache fähiger wird, während sie gleich groß bleibt – dieselbe Sparsamkeit der Mittel, die Thompson und Ritchie beim Bau von Unix aus kleinen, kombinierbaren Teilen anwandten.

Lassen Sie die Beschränkung das Werkzeug entwerfen. Lua existiert, weil Brasiliens Handelsschranken Tecgraf zwangen, seine eigene Software zu bauen, und seine Portabilität existiert, weil die Kunden des Labors „eine sehr vielfältige Sammlung von Computerplattformen” betrieben.3 Statt diese Beschränkungen als Behinderungen zu behandeln, ließ Ierusalimschy sie den Entwurf zu etwas Kleinerem, Saubererem und Portablerem treiben, als ein gut ausgestattetes Team wohl gebaut hätte – die Lehre, dass Knappheit, ernst genommen, ein Entwurfswerkzeug ist und keine Ausrede.3

Einflusskette

Wer ihn prägte

Scheme und die Lisp-Tradition. Die Entwickler sagen ausdrücklich, dass „der Einfluss von Scheme auf Lua allmählich zugenommen hat” und zu „einer Inspirationsquelle wurde, insbesondere mit der Einführung anonymer Funktionen und vollständiger lexikalischer Geltungsbereiche”. Wie Scheme ist Lua dynamisch typisiert, behandelt Funktionen als gewöhnliche vollwertige Werte und hält den Kern klein – die Überzeugung, dass eine Sprache mächtig sein kann, indem sie minimal statt umfangreich ist. (Prägender Einfluss)

DEL und SOL, die zwei kleinen Sprachen. Lua entsprang nicht der Theorie; es wuchs aus zwei für Petrobras gebauten domänenspezifischen Sprachen heraus. SOL steuerte die Tabellenkonstruktor-Syntax zur Beschreibung von Daten bei, und die Erfahrung mit beiden lehrte das Team, dass „große Teile komplexer Anwendungen mithilfe einbettbarer Skriptsprachen geschrieben werden konnten” – die Erkenntnis, auf der nach ihren eigenen Worten die Geburt von Lua beruhte.3 (Direkter Einfluss)

Brasiliens Marktvorbehalt. Die Handelsschranken, die von 1977 bis 1992 galten, sind ein unwahrscheinlicher, aber echter Einfluss: Sie sind der Grund, warum Tecgraf überhaupt seine eigenen Werkzeuge baute, und die Vielfalt der Plattformen seiner Kunden ist der Grund, warum Portabilität zu einem erstrangigen Entwurfsziel wurde. Die Politik machte die Sprache. (Prägender Einfluss)

Wen er prägte

Die Skriptschicht der Spielebranche. Von Grim Fandango an wurde Lua zu einem Quasi-Standard für das Einbetten von Spiellogik, und das Muster, das es populär machte – schnelle Engine in C++, bearbeitbares Verhalten in einem eingebetteten Skript – ist heute gängige Praxis. Robloxs Luau hat eine Generation von Kindern das Programmieren in einem Lua-Dialekt gelehrt. (Feldprägender Einfluss)

Eingebettete und Systemsoftware. Redis, nginx/OpenResty, Wireshark, Neovim und unzählige Geräte übernahmen Lua als Skriptschicht gerade deshalb, weil es so wenig verlangt. Wenige Sprachen reichen von einer Datenbank über einen Netzwerkanalysator bis zu einem Roboter, der auf nacktem Metall läuft.

Sprachentwerfer, die Kleinheit schätzen. Lua steht als lebender Beweis dafür, dass ein winziger, paradigmenagnostischer Kern große, meinungsstarke Sprachen in der Einbettungsnische ausstechen kann – ein Argument, das durch jeden minimalen Laufzeitumgebungs- und „Mechanismus statt Framework”-Entwurf seither nachhallt.

Der rote Faden

Ierusalimschy sitzt an einem Pol der langen Auseinandersetzung dieser Reihe darüber, wie viel ein Werkzeug für Sie entscheiden sollte. Guido van Rossum baute Python auf dem Grundsatz „es sollte einen offensichtlichen Weg geben, es zu tun” und lieferte alles inklusive mit – die Sprache hat Meinungen, und ihnen zu folgen ist der Weg des geringsten Widerstands. Bjarne Stroustrup baute C++ reich genug, um nahezu jedes Paradigma auszudrücken, und bezahlte diesen Reichtum mit Größe und Komplexität. Ierusalimschy ging den entgegengesetzten Weg zu beiden: liefere fast keine Vorgaben, fast keine Merkmale, nur ein paar allgemeine Mechanismen und eine 17.000 Zeilen lange Laufzeitumgebung, und lass den Benutzer den Rest bauen. Er ist das Software-Spiegelbild von Sophie Wilson, deren ARM gewann, indem es auf weniger als 25.000 Transistoren reduziert wurde – Lua ist dieselbe schonungslose Kleinheit in C, und wie ARMs zufälliger niedriger Stromverbrauch erwies sich seine Kleinheit als genau das, was es eine Domäne (das Einbetten) erobern ließ, für die es niemand entworfen hatte. Wo van Rossum sagt hier ist der offensichtliche Weg und Stroustrup sagt hier ist jeder Weg, sagt Ierusalimschy: hier sind die Hebel – Sie entscheiden, was Sie bauen, und ich halte das Ganze klein genug, um es überallhin mitzunehmen. (Reihenbrücke)

Was ich daraus mitnehme

Die Lehre, die ich von Ierusalimschy behalte, ist, dass das Stärkste, was Sie jemandem geben können, ein Mechanismus ist, keine Vorgabe. Es ist verlockend, wenn man ein Werkzeug baut, die eigene Meinung darüber, wie es verwendet werden sollte, fest einzubacken – das Klassensystem mitzuliefern, das Framework, den einen gesegneten Arbeitsablauf. Luas gesamte Laufbahn ist ein Argument dafür, dass das Gegenteil besser altert. Indem die Sprache es ablehnte, ein Objektmodell festzulegen, und stattdessen die Metatabelle lieferte, ließ sie Benutzer Vererbungsschemata bauen, die ihre Entwickler nie ersonnen hatten, in Spielen und Datenbanken und Editoren, die sie nie vorausgesehen hatten. Wenn ich heute etwas baue, ist die Frage, die ich Lua entlehne, ob ich eine Entscheidung oder eine Fähigkeit ausliefere – denn die Entscheidung dient den Fällen, die ich heute sehen kann, und die Fähigkeit dient denen, die ich nicht sehen kann.

Die zweite Lehre ist, dass Kleinheit keine Beschränkung ist, die Sie hinnehmen – sie ist eine Eigenschaft, die Sie schützen. Es wäre leicht gewesen, über dreißig Jahre des Benutzerdrucks hinweg, Lua zu einer großen Sprache mit einem Klassen-Schlüsselwort und einer Thread-Bibliothek und einem Standard-Framework für alles anwachsen zu lassen. Das Team weigerte sich, und die Weigerung ist der Grund, warum Lua auf eine Diskette passt, überall kompiliert und sich in das nackte Metallgehirn eines Roboters einbettet. Die Disziplin, klein zu bleiben – zu verallgemeinern statt anzuhäufen, die Funktion abzulehnen, bis man den Mechanismus darunter findet – ist schwerer als die Disziplin des Hinzufügens und weit wertvoller. Es ist Qualität ist die einzige Variable, gelesen als Zurückhaltung: die richtige kleine Sache, über Jahrzehnte verteidigt, wird zur Infrastruktur, auf der alles andere stehen kann.

FAQ

Wer ist Roberto Ierusalimschy und was hat er geschaffen?

Roberto Ierusalimschy ist ein brasilianischer Informatiker, geboren 1960 in Rio de Janeiro und ordentlicher Professor für Informatik an der PUC-Rio. Er ist der leitende Entwerfer von Lua, der kleinen, schnellen, einbettbaren Skriptsprache, die er 1993 im Tecgraf-Labor der PUC-Rio gemeinsam mit Luiz Henrique de Figueiredo und Waldemar Celes schuf. Er ist außerdem Autor des Buches Programming in Lua und Schöpfer von LPeg, einer Bibliothek zum Mustervergleich, und Mitautor der maßgeblichen Geschichte der Sprache, „The Evolution of Lua”.356

Was bedeutet „Mechanismen statt Vorgaben” in Lua?

Es bedeutet, dass Lua Ihnen einige wenige mächtige, allgemeine Mechanismen gibt, statt feste Entscheidungen aufzuzwingen. Das deutlichste Beispiel ist die Objektorientierung: Lua hat kein eingebautes Klassensystem. Stattdessen bietet es Tabellen (die sowohl Daten als auch Methoden aufnehmen können) und Metatabellen (die Ihnen erlauben, das Verhalten einer Tabelle anzupassen), und Sie bauen Vererbung, Klassen oder jedes andere Objektmodell selbst. Die Entwickler schrieben, dass „Lua dem Programmierer kein Objekt- oder Klassenmodell aufzwingt”, und entschieden sich stattdessen, „flexible Mechanismen bereitzustellen” – eine Haltung, die sie seit 1993 beibehalten haben.3

Warum wird Lua in Spielen und eingebetteten Systemen so weit verbreitet eingesetzt?

Weil es von Anfang an darauf ausgelegt war, klein, schnell, portabel und leicht einzubetten zu sein. Die Referenzimplementierung umfasst rund 17.000 Zeilen sauberen ANSI-C-Codes, der fast überall kompiliert, der fertige Interpreter ist etwa 143 KB groß, und eine klar definierte C-API lässt ein Wirtsprogramm Lua vollständig steuern. Dieses Profil ist genau das, was eine Spiel-Engine oder ein eingebettetes Gerät braucht – Schwerstarbeit in C/C++, bearbeitbare Logik in kleinen Skripten – weshalb es World of Warcraft, Roblox (über Luau), Redis, nginx/OpenResty, Adobe Lightroom und Geräte bis hinunter zu nackten Metallrobotern skriptet.137

Woher kommt der Name „Lua”?

Lua bedeutet „Mond” auf Portugiesisch. Es wurde als Nachfolger einer früheren Tecgraf-Sprache namens SOL benannt – „Simple Object Language” und zugleich „Sonne” auf Portugiesisch. Ein Kollege bei Tecgraf, Carlos Henrique Levy, schlug den Namen „Lua” für die neue Sprache vor und vollendete so die Abfolge von Sonne zu Mond. Das gesamte Projekt erwuchs aus zwei kleinen Sprachen, DEL und SOL, die für den brasilianischen Ölkonzern Petrobras gebaut wurden.3


Quellen


  1. „Lua (programming language),” Wikipedia. Lua wurde 1993 von Roberto Ierusalimschy, Luiz Henrique de Figueiredo und Waldemar Celes in der Computer Graphics Technology Group (Tecgraf) an der Päpstlichen Katholischen Universität von Rio de Janeiro (PUC-Rio), Brasilien, geschaffen; in ANSI C implementiert, MIT-lizenziert, mit einer registerbasierten virtuellen Maschine seit Lua 5.0, Garbage Collection, Coroutinen und vollwertigen Funktionen. Aktuelle Referenzimplementierungen bleiben klein (der Artikel merkt an, dass Lua 5.5.0 etwa 32.000 Zeilen C umfasst). Dokumentierte Anwender sind die Spiele World of Warcraft, Roblox (das Luau, eine Lua-Ableitung, entwickelte), Dota 2, Crysis und Garry’s Mod sowie Nicht-Spiele-Software wie Redis, nginx (über OpenResty), Adobe Lightroom, Wireshark und Neovim. 

  2. „Roberto Ierusalimschy: Known for Lua Programming Language,” machaddr (biografisches Profil). Fasst Ierusalimschys Rolle als Schöpfer und leitender Architekt von Lua zusammen, entwickelt mit Luiz Henrique de Figueiredo und Waldemar Celes an der PUC-Rio, erstmals 1993 veröffentlicht; vermerkt Luas weltweiten Einsatz in Software wie World of Warcraft und Adobe Lightroom, seine Autorschaft von Programming in Lua und seine Schöpfung der LPeg-Bibliothek. 

  3. Roberto Ierusalimschy, Luiz Henrique de Figueiredo und Waldemar Celes, „The Evolution of Lua,” Proceedings of the Third ACM SIGPLAN Conference on the History of Programming Languages (HOPL III), 2007. Primärquelle. „Lua ist eine Skriptsprache, die 1993 an der PUC-Rio entstand.” „Von Anfang an wurde Lua so entworfen, dass es einfach, klein, portabel, schnell und leicht in Anwendungen einzubetten ist.” Die einzige Datenstruktur: „es bietet eine einzige Art von Datenstruktur, die Tabelle.” Implementiert in „sauberem C,” „der Schnittmenge von C und C++,” und „kompiliert auf den meisten Plattformen ohne Anpassung.” Geringe Größe: der Quelltext von Lua 5.1 umfasst „rund 17.000 Zeilen C,” der Tarball „passt bequem auf eine Diskette,” und „der mit allen Standard-Lua-Bibliotheken gebaute Lua-Interpreter belegt 143K.” „über 40 % von Adobe Lightroom sind in Lua geschrieben (das entspricht rund 100.000 Zeilen Lua-Code).” Zu Brasiliens Handelspolitik: „Von 1977 bis 1992 hatte Brasilien eine Politik starker Handelsschranken (genannt ‚Marktvorbehalt’) für Computerhardware und -software,” und „diese Gründe brachten Tecgraf dazu, die grundlegenden Werkzeuge, die es brauchte, von Grund auf selbst zu bauen”; Lua ist „die einzige Sprache, die in einem Entwicklungsland geschaffen wurde und globale Bedeutung erlangt hat.” Vorläufer DEL („data-entry language”) und SOL („Simple Object Language”). Namensgebung: SOL ist Sonne auf Portugiesisch, und „ein Freund bei Tecgraf (Carlos Henrique Levy) schlug den Namen ‚Lua’ (Mond auf Portugiesisch) vor, und Lua war geboren.” Erste Implementierung fertiggestellt im Juli 1993, „dem Einfachsten, was möglicherweise funktionieren könnte” folgend. Zu „Mechanismen statt Vorgaben”: „wir wollten Lua nicht in eine objektorientierte Sprache verwandeln, weil wir kein Programmierparadigma für Lua festlegen wollten”; „Lua zwingt dem Programmierer kein Objekt- oder Klassenmodell auf”; „wir entschieden uns, flexible Mechanismen bereitzustellen, die es dem Programmierer erlauben würden, das jeweils zur Anwendung passende Modell zu bauen”; „Erweiterbare Semantik ist zu einem Markenzeichen von Lua geworden.” Entwicklung des Mechanismus: Fallbacks (Lua 2.1, 1995) → Tag-Methoden (Lua 3.0, 1997) → Metatabellen und Metamethoden (Lua 5.0, 2003); Tabellenindex-Fallbacks unterstützten „viele Formen der Vererbung (durch Delegation)”; der Begriff „Metatabelle” wurde 2001 von Rici Lake vorgeschlagen. Lua als „erweiterbare Erweiterungssprache” mit einer C-API, die „vollständige Kommunikation zwischen Lua-Code und externem Code” erlaubt. Spiele: Im Januar 1997 berichtete Bret Mogilefsky, leitender Programmierer von LucasArts’ Grim Fandango, dass „ein gewaltiger Anteil des Spiels in Lua geschrieben war”, woraufhin „sich Lua mündlich unter Spieleentwicklern verbreitete und zu einer durchaus marktfähigen Fähigkeit in der Spielebranche wurde.” Nebenläufigkeit: Die Umsetzung präemptiver Threads erfordert Primitive, „die nicht Teil von ANSI C sind”, und „wir glaubten (und glauben noch immer) nicht an das übliche Multithreading-Modell… niemand kann korrekte Programme in einer Sprache schreiben, in der ‚a=a+1’ nicht deterministisch ist”; kooperatives Multitasking über Coroutinen wurde in Lua 5.0 (2003) bereitgestellt. VM: „Seit Lua 5.0 ist die virtuelle Maschine registerbasiert,” und „die virtuelle Maschine von Lua 5.0 war die erste registerbasierte virtuelle Maschine mit breiter Verwendung”; inkrementelle Garbage Collection erscheint in Lua 5.1. 

  4. „Lua: about,” Lua.org (offizielle Website). „Lua ist eine mächtige, effiziente, leichtgewichtige, einbettbare Skriptsprache.” Es „ist als kleine Bibliothek von C-Funktionen implementiert, geschrieben in sauberem C, der gemeinsamen Teilmenge von Standard-C und C++,” und „läuft auf allen Arten von Unix- und Windows-Systemen sowie auf mobilen Geräten… eingebetteten Mikroprozessoren… und IBM-Großrechnern.” Beschreibt Lua als Verbindung von „einfacher prozeduraler Syntax mit mächtigen Konstrukten zur Datenbeschreibung auf Basis assoziativer Arrays und erweiterbarer Semantik”, mit dynamischer Typisierung, automatischer Speicherverwaltung mit inkrementeller Garbage Collection und als „schnell” und „portabel”. 

  5. „Roberto Ierusalimschy,” Wikipedia, bestätigt durch sein „Fakultätsprofil,” Department of Informatics, PUC-Rio. Geboren am 21. Mai 1960 in Rio de Janeiro, Brasilien; PhD in Informatik von der PUC-Rio (1990); ordentlicher Professor für Informatik an der PUC-Rio; Postdoc-Arbeit an der University of Waterloo und Gastprofessor in Stanford (2012). Schöpfer und leitender Architekt der Programmiersprache Lua, Autor von Programming in Lua (vier Auflagen) und Entwickler von LPeg, einer Lua-Bibliothek zur Umsetzung von Parsing Expression Grammars. 

  6. „Programming in Lua,” von Roberto Ierusalimschy, Lua.org. Das offizielle Buch über Lua, geschrieben von seinem leitenden Entwerfer, das Entwurf und Verwendung der Sprache beschreibt; die erste Auflage ist online frei verfügbar. Bekräftigt Luas Entwurf rund um Tabellen als alleinigen Mechanismus zur Datenstrukturierung, Metatabellen für erweiterbares Verhalten, vollwertige Funktionen und Coroutinen für kooperatives Multitasking. 

  7. Roberto Ierusalimschy, Luiz Henrique de Figueiredo und Waldemar Celes, „The Evolution of Lua,” HOPL III, 2007, Fußnote zum eingebetteten Einsatz. „Crazy Ivan, ein Roboter, der 2000 und 2001 in Dänemark den RoboCup gewann, hatte ein in Lua implementiertes ‚Gehirn’. Lua lief direkt auf einem Motorola-Coldfire-5206e-Prozessor ohne jedes Betriebssystem (mit anderen Worten, Lua war das Betriebssystem). Lua war in einem System-ROM gespeichert und lud Programme beim Start über den seriellen Anschluss.” Veranschaulicht Luas Reichweite in nackte eingebettete Geräte, eine Folge seiner kleinen, portablen Implementierung. 

Verwandte Beiträge

Engineering-Philosophie: Guido van Rossum, Lesbarkeit zählt

Guido van Rossum baute Python auf einer einzigen Wette auf: Code wird weit häufiger gelesen als geschrieben, also sollte…

15 Min. Lesezeit

Engineering-Philosophie: Grace Hopper – bringen Sie den Computer dazu, menschlich zu sprechen

Grace Hopper baute den ersten Compiler, damit Programme in menschlicher Sprache geschrieben werden konnten, machte Laten…

16 Min. Lesezeit

The Shader Gallery That Lied: Debugging 216 WebGL Presets

A user said the shader playground looked broken. Pixel-readback testing found 30 dead presets, 11 that never compiled, a…

11 Min. Lesezeit