Loading...

DIE HUNDERTJÄHRIGE SPRACHE

Original

April 2003

(Dieser Aufsatz basiert auf einem Grundsatzvortrag auf der PyCon 2003.)

Es ist schwer vorherzusagen, wie das Leben in hundert Jahren aussehen wird. Es gibt nur wenige Dinge, die wir mit Sicherheit sagen können. Wir wissen, dass jeder fliegende Autos fahren wird, dass die Bauvorschriften gelockert werden, um Gebäude mit Hunderten von Stockwerken zuzulassen, dass es die meiste Zeit dunkel sein wird und dass alle Frauen in Kampfsportarten ausgebildet sein werden. Hier möchte ich auf ein Detail dieses Bildes näher eingehen. Welche Art von Programmiersprache wird man verwenden, um die Software zu schreiben, die diese fliegenden Autos steuert?

Das ist nicht so sehr eine Überlegung wert, weil wir diese Sprachen tatsächlich verwenden werden, sondern weil wir – wenn wir Glück haben – auf dem Weg von diesem Punkt zu jenem Sprachen verwenden werden.

Ich denke, dass Sprachen wie Arten evolutionäre Bäume bilden werden, die überall Sackgassen bilden. Wir können das bereits beobachten. Cobol scheint trotz seiner zeitweiligen Popularität keine intellektuellen Nachkommen zu haben. Es ist eine evolutionäre Sackgasse – eine Neandertalersprache.

Ich sage Java ein ähnliches Schicksal voraus. Manchmal schreiben mir Leute E-Mails mit der Frage: „Wie können Sie sagen, dass Java keine erfolgreiche Sprache sein wird? Es ist bereits eine erfolgreiche Sprache.“ Und ich gebe zu, dass es das ist, wenn man den Erfolg daran misst, wie viel Bücher (insbesondere einzelne Bücher) in den Regalen darüber stehen, oder an der Zahl der Studenten, die glauben, sie müssten Java lernen, um einen Job zu bekommen. Wenn ich sage, dass Java keine erfolgreiche Sprache sein wird, meine ich etwas Konkreteres: dass Java sich als evolutionäre Sackgasse herausstellen wird, wie Cobol.

Das ist nur eine Vermutung. Ich kann mich irren. Mir geht es hier nicht darum, Java schlecht zu machen, sondern das Thema der Evolutionsbäume anzusprechen und die Leute fragen zu lassen, wo auf dem Baum Sprache X liegt. Der Grund, diese Frage zu stellen, ist nicht nur, dass unsere Geister in hundert Jahren sagen können: „Ich hab’s dir ja gesagt.“ Der Grund ist, dass es eine nützliche Heuristik ist, sich an die Hauptzweige zu halten, um Sprachen zu finden, in denen man jetzt gut programmieren kann.

Zu jeder Zeit fühlt man sich wahrscheinlich auf den Hauptästen eines Evolutionsbaums am wohlsten. Selbst als es noch viele Neandertaler gab, muss es ätzend gewesen sein, einer zu sein. Die Cro-Magnons wären ständig zu dir gekommen, hätten dich verprügelt und dir dein Essen gestohlen.

Der Grund, warum ich wissen möchte, wie die Sprachen in hundert Jahren aussehen werden, besteht darin, dass ich jetzt weiß, auf welchen Zweig des Baumes ich setzen soll.

Die Evolution der Sprachen unterscheidet sich von der Evolution der Arten, da Zweige zusammenlaufen können. Der Fortran-Zweig scheint beispielsweise mit den Nachkommen von Algol zu verschmelzen. Theoretisch ist dies auch bei Arten möglich, aber es ist unwahrscheinlich, dass dies bei etwas passiert, das größer als eine Zelle ist.

Konvergenz ist bei Sprachen wahrscheinlicher, zum Teil weil der Raum der Möglichkeiten kleiner ist und zum Teil weil Mutationen nicht zufällig sind. Sprachentwickler integrieren bewusst Ideen aus anderen Sprachen.

Besonders nützlich ist es für Sprachentwickler, darüber nachzudenken, wohin die Entwicklung von Programmiersprachen wahrscheinlich führen wird, denn sie können sich entsprechend darauf einstellen. In diesem Fall wird „bei einem Hauptzweig bleiben“ zu mehr als nur einer Möglichkeit, eine gute Sprache auszuwählen. Es wird zu einer Heuristik, um die richtigen Entscheidungen beim Sprachdesign zu treffen.

Jede Programmiersprache kann in zwei Teile unterteilt werden: einen Satz grundlegender Operatoren, die die Rolle von Axiomen spielen, und den Rest der Sprache, der im Prinzip mithilfe dieser grundlegenden Operatoren geschrieben werden könnte.

Ich denke, die grundlegenden Operatoren sind der wichtigste Faktor für das langfristige Überleben einer Sprache. Den Rest können Sie ändern. Es ist wie die Regel, dass Sie beim Kauf eines Hauses zuerst die Lage berücksichtigen sollten. Alles andere können Sie später ändern, aber die Lage können Sie nicht ändern.

Ich denke, es ist nicht nur wichtig, dass die Axiome gut gewählt sind, sondern auch, dass es nur wenige davon gibt. Mathematiker haben schon immer so über Axiome gedacht – je weniger, desto besser – und ich denke, sie sind da einer Sache auf der Spur.

Zumindest muss es eine sinnvolle Übung sein, sich den Kern einer Sprache genau anzuschauen, um zu sehen, ob es irgendwelche Axiome gibt, die man ausmerzen könnte. Ich habe in meiner langen Karriere als Chaot festgestellt, dass Müll Müll erzeugt, und ich habe das in Software ebenso gesehen wie unter Betten und in Zimmerecken.

Ich habe das Gefühl, dass die Hauptäste des Evolutionsbaums durch die Sprachen verlaufen, die die kleinsten, saubersten Kerne haben. Je mehr von einer Sprache man in sich selbst schreiben kann, desto besser.

Natürlich gehe ich von einer großen Annahme aus, wenn ich überhaupt frage, wie Programmiersprachen in hundert Jahren aussehen werden. Werden wir in hundert Jahren überhaupt noch Programme schreiben? Werden wir den Computern dann nicht einfach sagen, was sie tun sollen?

In diesem Bereich hat es bisher keine großen Fortschritte gegeben. Ich schätze, dass die Menschen in hundert Jahren den Computern immer noch sagen werden, was sie tun sollen, indem sie Programme verwenden, die wir als solche erkennen. Es mag Aufgaben geben, die wir heute durch das Schreiben von Programmen lösen und für die man in hundert Jahren keine Programme mehr schreiben muss, aber ich denke, dass es noch immer viel Programmierung der Art geben wird, wie wir sie heute durchführen.

Es mag anmaßend erscheinen, zu glauben, dass irgendjemand vorhersagen kann, wie eine Technologie in hundert Jahren aussehen wird. Aber bedenken Sie, dass wir bereits fast fünfzig Jahre Geschichte hinter uns haben. Ein Blick in die Zukunft ist eine greifbare Vorstellung, wenn wir bedenken, wie langsam sich die Sprachen in den letzten fünfzig Jahren entwickelt haben.

Sprachen entwickeln sich langsam, weil sie keine wirklichen Technologien sind. Sprachen sind Notation. Ein Programm ist eine formale Beschreibung des Problems, das ein Computer für Sie lösen soll. Die Entwicklungsgeschwindigkeit von Programmiersprachen ähnelt also eher der Entwicklungsgeschwindigkeit der mathematischen Notation als beispielsweise der von Transport oder Kommunikation. Die mathematische Notation entwickelt sich zwar, aber nicht mit den riesigen Sprüngen, die man in der Technologie sieht.

Was auch immer Computer in hundert Jahren sein werden, man kann wohl mit Sicherheit vorhersagen, dass sie viel schneller sein werden als heute. Wenn das Mooresche Gesetz weiterhin gilt, werden sie 74 Trillionen (73.786.976.294.838.206.464) Mal schneller sein. Das ist ziemlich schwer vorstellbar. Und tatsächlich ist die wahrscheinlichste Vorhersage in Sachen Geschwindigkeit, dass das Mooresche Gesetz nicht mehr funktioniert. Alles, was sich alle achtzehn Monate verdoppeln soll, wird wahrscheinlich irgendwann an eine Art fundamentale Grenze stoßen. Aber ich kann ohne weiteres glauben, dass Computer sehr viel schneller sein werden. Selbst wenn sie am Ende nur eine mickrige Million Mal schneller sein werden, sollte das die Grundregeln für Programmiersprachen erheblich ändern. Unter anderem wird es mehr Raum für das geben, was heute als langsame Sprachen gelten würde, also Sprachen, die keinen sehr effizienten Code produzieren.

Und dennoch erfordern manche Anwendungen Geschwindigkeit. Manche der Probleme, die wir mit Computern lösen wollen, werden von Computern geschaffen. So hängt beispielsweise die Geschwindigkeit, mit der Sie Videobilder verarbeiten müssen, von der Geschwindigkeit ab, mit der ein anderer Computer sie erzeugen kann. Und es gibt eine weitere Klasse von Problemen, die von Natur aus eine unbegrenzte Kapazität haben, Zyklen aufzusaugen: Bildwiedergabe, Kryptographie, Simulationen.

Während manche Anwendungen immer ineffizienter werden, während andere weiterhin die volle Geschwindigkeit der Hardware fordern, werden schnellere Computer dazu führen, dass Sprachen ein immer breiteres Spektrum an Effizienz abdecken müssen. Das haben wir bereits erlebt. Die aktuellen Implementierungen einiger beliebter neuer Sprachen sind im Vergleich zu den Standards früherer Jahrzehnte erschreckend verschwenderisch.

Das ist nicht nur etwas, das bei Programmiersprachen passiert. Es ist ein allgemeiner historischer Trend. Mit der Weiterentwicklung der Technologien kann jede Generation Dinge tun, die die vorherige Generation als Verschwendung angesehen hätte. Die Leute vor dreißig Jahren wären erstaunt gewesen, wie selbstverständlich wir Ferngespräche führen. Die Leute vor hundert Jahren wären noch erstaunter gewesen, dass eines Tages ein Paket von Boston über Memphis nach New York reisen würde.

Ich kann Ihnen jetzt schon sagen, was mit all den zusätzlichen Zyklen passieren wird, die uns die schnellere Hardware in den nächsten hundert Jahren bescheren wird. Sie werden fast alle verschwendet.

Ich habe das Programmieren gelernt, als Computerleistung noch knapp war. Ich kann mich daran erinnern, wie ich alle Speicherplätze aus meinen Basic-Programmen entfernt habe, damit sie in den Speicher eines 4K TRS-80 passen. Der Gedanke an all diese unglaublich ineffiziente Software, die Zyklen verschlingt, indem sie immer wieder dasselbe tut, erscheint mir irgendwie widerlich. Aber ich glaube, meine Intuitionen sind hier falsch. Ich bin wie jemand, der in Armut aufgewachsen ist und es nicht ertragen kann, Geld auszugeben, selbst für etwas Wichtiges wie einen Arztbesuch.

Manche Arten von Verschwendung sind wirklich ekelhaft. SUVs zum Beispiel wären wohl auch dann ekelhaft, wenn sie mit einem Kraftstoff betrieben würden, der niemals ausgehen würde und keine Umweltverschmutzung verursachte. SUVs sind ekelhaft, weil sie die Lösung für ein ekelhaftes Problem sind. (Wie man Minivans männlicher aussehen lässt.) Aber nicht jede Verschwendung ist schlecht. Jetzt, da wir die Infrastruktur haben, um dies zu unterstützen, beginnt das Zählen der Minuten Ihrer Ferngespräche lästig zu werden. Wenn Sie die Ressourcen haben, ist es eleganter, alle Telefongespräche als eine Sache zu betrachten, egal, wo sich die andere Person befindet.

Es gibt gute Verschwendung und schlechte Verschwendung. Mich interessiert gute Verschwendung – die Art, bei der wir durch höhere Ausgaben einfachere Designs erhalten können. Wie können wir die Gelegenheit nutzen, Zyklen zu verschwenden, die wir durch neue, schnellere Hardware erhalten?

Der Wunsch nach Geschwindigkeit ist in uns, unseren mickrigen Computern, so tief verwurzelt, dass es einer bewussten Anstrengung bedarf, ihn zu überwinden. Beim Sprachdesign sollten wir bewusst nach Situationen suchen, in denen wir Effizienz gegen den kleinsten Komfortgewinn eintauschen können.

Die meisten Datenstrukturen existieren wegen der Geschwindigkeit. Viele Sprachen haben heute beispielsweise sowohl Zeichenfolgen als auch Listen. Semantisch gesehen sind Zeichenfolgen mehr oder weniger eine Teilmenge von Listen, deren Elemente Zeichen sind. Warum also brauchen Sie einen separaten Datentyp? Eigentlich nicht. Zeichenfolgen existieren nur aus Effizienzgründen. Aber es ist lahm, die Semantik der Sprache mit Hacks zu überladen, um Programme schneller laufen zu lassen. Zeichenfolgen in einer Sprache zu haben, scheint ein Fall von vorzeitiger Optimierung zu sein.

Wenn wir den Kern einer Sprache als eine Reihe von Axiomen betrachten, ist es sicherlich widerlich, zusätzliche Axiome zu haben, die keine Ausdruckskraft hinzufügen, nur um der Effizienz willen. Effizienz ist wichtig, aber ich glaube nicht, dass dies der richtige Weg ist, um sie zu erreichen.

Der richtige Weg, dieses Problem zu lösen, besteht meiner Meinung nach darin, die Bedeutung eines Programms von den Implementierungsdetails zu trennen. Anstatt sowohl Listen als auch Zeichenfolgen zu verwenden, sollten Sie nur Listen verwenden und dem Compiler eine Möglichkeit geben, Optimierungshinweise zu geben, die es ihm ermöglichen, Zeichenfolgen bei Bedarf als zusammenhängende Bytes anzulegen.

Da die Geschwindigkeit bei den meisten Programmen keine Rolle spielt, müssen Sie sich normalerweise nicht mit dieser Art von Mikromanagement befassen. Dies gilt umso mehr, je schneller Computer werden.

Weniger über die Implementierung zu sagen, sollte auch die Programme flexibler machen. Spezifikationen ändern sich während des Schreibens eines Programms, und das ist nicht nur unvermeidlich, sondern auch wünschenswert.

Das Wort „Essay“ kommt vom französischen Verb „essayer“, was „versuchen“ bedeutet. Ein Essay ist im ursprünglichen Sinne etwas, das man schreibt, um zu versuchen, etwas herauszufinden. Das passiert auch bei Software. Ich denke, einige der besten Programme waren Essays, in dem Sinne, dass die Autoren nicht wussten, als sie anfingen, was genau sie zu schreiben versuchten.

Lisp-Hacker wissen bereits, wie wertvoll es ist, bei Datenstrukturen flexibel zu sein. Wir neigen dazu, die erste Version eines Programms so zu schreiben, dass es alles mit Listen macht. Diese ersten Versionen können so erschreckend ineffizient sein, dass man sich bewusst anstrengen muss, nicht darüber nachzudenken, was sie tun – so wie ich mich zumindest beim Essen eines Steaks bewusst anstrengen muss, nicht darüber nachzudenken, woher es kommt.

Was Programmierer in hundert Jahren vor allem suchen werden, ist eine Sprache, mit der man mit möglichst geringem Aufwand eine unglaublich ineffiziente Version 1 eines Programms zusammenschustern kann. Zumindest würden wir es heute so beschreiben. Sie werden sagen, dass sie eine Sprache wollen, in der sich leicht programmieren lässt.

Ineffiziente Software ist nicht schlimm. Schlimm ist eine Sprache, die Programmierer unnötige Arbeit machen lässt. Die wahre Ineffizienz liegt in der Zeitverschwendung der Programmierer, nicht in der Zeitverschwendung der Maschine. Das wird immer deutlicher, je schneller die Computer werden.

Ich denke, dass wir uns schon jetzt Gedanken darüber machen könnten, Strings loszuwerden. Wir haben es in Arc getan und es scheint ein Erfolg zu sein; einige Operationen, die als reguläre Ausdrücke schwer zu beschreiben wären, können problemlos als rekursive Funktionen beschrieben werden.

Wie weit wird diese Verflachung der Datenstrukturen gehen? Ich kann mir Möglichkeiten vorstellen, die selbst mich mit meinem durch mein Gewissen erweiterten Horizont schockieren. Werden wir beispielsweise Arrays loswerden? Schließlich sind sie nur eine Teilmenge von Hash-Tabellen, deren Schlüssel Vektoren von Ganzzahlen sind. Werden wir die Hash-Tabellen selbst durch Listen ersetzen?

Es gibt sogar noch schockierendere Aussichten. Das Lisp, das McCarthy 1960 beschrieb, hatte beispielsweise keine Zahlen. Logischerweise braucht man kein separates Zahlenkonzept, da man sie als Listen darstellen kann: Die Ganzzahl n könnte als Liste mit n Elementen dargestellt werden. Auf diese Weise kann man Mathematik betreiben. Es ist nur unerträglich ineffizient.

Niemand hat tatsächlich vorgeschlagen, Zahlen in der Praxis als Listen zu implementieren. Tatsächlich war McCarthys Aufsatz von 1960 damals überhaupt nicht für eine Implementierung vorgesehen. Es war eine theoretische Übung , ein Versuch, eine elegantere Alternative zur Turing-Maschine zu schaffen. Als jemand unerwarteterweise diesen Aufsatz nahm und ihn in einen funktionierenden Lisp-Interpreter übersetzte, wurden Zahlen ganz sicher nicht als Listen dargestellt; sie wurden binär dargestellt, wie in jeder anderen Sprache.

Könnte eine Programmiersprache so weit gehen, Zahlen als grundlegenden Datentyp abzuschaffen? Ich stelle diese Frage nicht so sehr als ernste Frage, sondern als eine Art, mit der Zukunft zu spielen. Es ist wie der hypothetische Fall einer unwiderstehlichen Kraft, die auf ein unbewegliches Objekt trifft – hier trifft eine unvorstellbar ineffiziente Implementierung auf unvorstellbar große Ressourcen. Ich sehe keinen Grund, warum nicht. Die Zukunft ist ziemlich lang. Wenn wir etwas tun können, um die Anzahl der Axiome in der Kernsprache zu verringern, scheint das die Seite zu sein, auf die man setzen sollte, wenn t gegen unendlich geht. Wenn die Idee in hundert Jahren immer noch unerträglich erscheint, wird sie es in tausend Jahren vielleicht nicht mehr sein.

Um das klarzustellen: Ich schlage nicht vor, dass alle numerischen Berechnungen tatsächlich mithilfe von Listen durchgeführt werden. Ich schlage vor, dass die Kernsprache, bevor weitere Notationen zur Implementierung gemacht werden, auf diese Weise definiert wird. In der Praxis würde jedes Programm, das mathematische Berechnungen durchführen möchte, Zahlen wahrscheinlich binär darstellen, aber dies wäre eine Optimierung und kein Teil der Semantik der Kernsprache.

Eine weitere Möglichkeit, Zyklen zu verschlingen, besteht darin, viele Softwareschichten zwischen der Anwendung und der Hardware zu platzieren. Auch das ist ein Trend, den wir bereits beobachten: Viele neuere Sprachen werden in Bytecode kompiliert. Bill Woods hat mir einmal gesagt, dass jede Interpretationsschicht als Faustregel einen Faktor 10 an Geschwindigkeit kostet. Diese zusätzlichen Kosten erkaufen Sie sich mit Flexibilität.

Die allererste Version von Arc war ein Extremfall dieser Art von mehrstufiger Langsamkeit, mit entsprechenden Vorteilen. Es war ein klassischer „metazirkulärer“ Interpreter, der auf Common Lisp geschrieben wurde und eine deutliche Ähnlichkeit mit der eval-Funktion aufwies, die in McCarthys ursprünglichem Lisp-Artikel definiert wurde. Das Ganze bestand nur aus ein paar hundert Zeilen Code, war also sehr leicht zu verstehen und zu ändern. Das von uns verwendete Common Lisp, CLisp, läuft selbst auf einem Bytecode-Interpreter. Hier hatten wir also zwei Interpretationsebenen, von denen eine (die oberste) erschreckend ineffizient war, und die Sprache war brauchbar. Kaum brauchbar, gebe ich zu, aber brauchbar.

Das Schreiben von Software in mehreren Schichten ist selbst innerhalb von Anwendungen eine leistungsfähige Technik. Bottom-up-Programmierung bedeutet, ein Programm in einer Reihe von Schichten zu schreiben, von denen jede als Sprache für die darüber liegende dient. Dieser Ansatz führt tendenziell zu kleineren, flexibleren Programmen. Es ist auch der beste Weg zum heiligen Gral der Wiederverwendbarkeit. Eine Sprache ist per Definition wiederverwendbar. Je mehr von Ihrer Anwendung Sie in eine Sprache zum Schreiben dieser Art von Anwendung übertragen können, desto mehr von Ihrer Software wird wiederverwendbar sein.

Irgendwie wurde die Idee der Wiederverwendbarkeit in den 1980er Jahren mit der objektorientierten Programmierung verknüpft, und kein noch so großer Beweis des Gegenteils scheint sie davon abbringen zu können. Obwohl manche objektorientierte Software wiederverwendbar ist, ist es ihre Bottom-up-Struktur, die sie wiederverwendbar macht, und nicht ihre Objektorientierung. Betrachten wir Bibliotheken: Sie sind wiederverwendbar, weil sie eine Sprache sind, unabhängig davon, ob sie in einem objektorientierten Stil geschrieben sind oder nicht.

Ich sage übrigens nicht den Untergang der objektorientierten Programmierung voraus. Obwohl ich nicht glaube, dass sie guten Programmierern außer in bestimmten Spezialbereichen viel zu bieten hat, ist sie für große Organisationen unwiderstehlich. Die objektorientierte Programmierung bietet eine nachhaltige Möglichkeit, Spaghetticode zu schreiben. Sie ermöglicht es Ihnen, Programme als eine Reihe von Patches anzuhäufen.

Große Unternehmen tendieren schon immer dazu, ihre Software auf diese Weise zu entwickeln und ich gehe davon aus, dass dies in hundert Jahren genauso der Fall sein wird wie heute.

Wenn wir über die Zukunft sprechen, sollten wir besser über parallele Berechnungen sprechen, denn dort scheint diese Idee zu existieren. Das heißt, egal wann Sie darüber sprechen, parallele Berechnungen scheinen etwas zu sein, das in der Zukunft passieren wird.

Wird die Zukunft das jemals einholen? Seit mindestens 20 Jahren wird über die Parallelverarbeitung als etwas Unmittelbares gesprochen, und bisher hat sie die Programmierpraxis nicht groß beeinflusst. Oder etwa nicht? Chipdesigner müssen bereits jetzt darüber nachdenken, und das gilt auch für Leute, die versuchen, Systemsoftware auf Multi-CPU-Computern zu schreiben.

Die eigentliche Frage ist, wie weit wird die Parallelität auf der Abstraktionsleiter reichen? Wird sie in hundert Jahren sogar Anwendungsprogrammierer betreffen? Oder wird sie etwas sein, worüber Compiler-Autoren nachdenken, das aber im Quellcode von Anwendungen normalerweise unsichtbar ist?

Eines scheint jedoch wahrscheinlich: Die meisten Möglichkeiten zur Parallelität werden ungenutzt bleiben. Dies ist ein Sonderfall meiner allgemeineren Vorhersage, dass der Großteil der zusätzlichen Computerleistung, die uns zur Verfügung steht, ungenutzt bleiben wird. Ich gehe davon aus, dass Parallelität – wie die enorme Geschwindigkeit der zugrunde liegenden Hardware – etwas sein wird, das verfügbar ist, wenn man es explizit anfordert, aber normalerweise nicht genutzt wird. Dies bedeutet, dass die Art von Parallelität, die wir in hundert Jahren haben werden, außer in speziellen Anwendungen, keine massive Parallelität sein wird. Ich gehe davon aus, dass es für normale Programmierer eher so sein wird, als könnten sie Prozesse abspalten, die am Ende alle parallel laufen.

Und dies wird, wie die Anforderung spezifischer Implementierungen von Datenstrukturen, etwas sein, das Sie erst recht spät im Lebenszyklus eines Programms tun, wenn Sie versuchen, es zu optimieren. Version 1 wird normalerweise alle Vorteile, die sich aus parallelen Berechnungen ergeben, ignorieren, genauso wie sie die Vorteile, die sich aus spezifischen Datendarstellungen ergeben, ignorieren wird.

Außer in speziellen Anwendungsfällen wird die Parallelität in den Programmen, die in hundert Jahren geschrieben werden, nicht allgegenwärtig sein. Es wäre eine verfrühte Optimierung, wenn dies der Fall wäre.

Wie viele Programmiersprachen wird es in hundert Jahren geben? In letzter Zeit scheint es eine riesige Anzahl neuer Programmiersprachen zu geben. Ein Grund dafür ist, dass schnellere Hardware es Programmierern ermöglicht hat, je nach Anwendung unterschiedliche Kompromisse zwischen Geschwindigkeit und Komfort einzugehen. Wenn dies ein echter Trend ist, sollte die Hardware, die wir in hundert Jahren haben werden, diesen nur noch verstärken.

Und dennoch wird es in hundert Jahren vielleicht nur noch wenige weit verbreitete Sprachen geben. Ein Grund, warum ich das sage, ist Optimismus: Es scheint, dass man, wenn man wirklich gute Arbeit leistet, eine Sprache entwickeln könnte, die ideal zum Schreiben einer langsamen Version 1 ist und dennoch mit den richtigen Optimierungsratschlägen für den Compiler bei Bedarf auch sehr schnellen Code liefert. Da ich also optimistisch bin, sage ich voraus, dass Programmierer in hundert Jahren trotz der großen Lücke zwischen akzeptabler und maximaler Effizienz Sprachen haben werden, die den größten Teil dieser Lücke abdecken können.

Mit zunehmender Kluft werden Profiler immer wichtiger. Dem Profiling wird derzeit wenig Aufmerksamkeit geschenkt. Viele Leute scheinen immer noch zu glauben, dass man schnelle Anwendungen bekommt, indem man Compiler schreibt, die schnellen Code erzeugen. Mit zunehmender Kluft zwischen akzeptabler und maximaler Leistung wird immer klarer, dass man schnelle Anwendungen bekommt, wenn man eine gute Orientierung zwischen beiden hat.

Wenn ich sage, dass es möglicherweise nur wenige Sprachen gibt, meine ich damit keine domänenspezifischen „kleinen Sprachen“. Ich halte solche eingebetteten Sprachen für eine großartige Idee und erwarte, dass sie sich verbreiten werden. Aber ich erwarte, dass sie so dünn geschrieben werden, dass Benutzer die darunterliegende Allzwecksprache erkennen können.

Wer wird die Sprachen der Zukunft entwickeln? Einer der aufregendsten Trends der letzten zehn Jahre war der Aufstieg von Open-Source-Sprachen wie Perl, Python und Ruby. Die Sprachentwicklung wird von Hackern übernommen. Die bisherigen Ergebnisse sind chaotisch, aber ermutigend. So gibt es beispielsweise in Perl einige verblüffend neuartige Ideen. Viele davon sind verblüffend schlecht, aber das gilt immer für ehrgeizige Bemühungen. Bei der derzeitigen Mutationsrate weiß Gott, wie sich Perl in hundert Jahren entwickeln könnte.

Es stimmt nicht, dass diejenigen, die etwas nicht können, unterrichten (einige der besten Hacker, die ich kenne, sind Professoren), aber es stimmt, dass es viele Dinge gibt, die diejenigen, die unterrichten, nicht tun können. Die Forschung unterliegt einschränkenden Kastenbeschränkungen. In jedem akademischen Bereich gibt es Themen, an denen man arbeiten darf, und andere, bei denen das nicht der Fall ist. Leider basiert die Unterscheidung zwischen akzeptablen und verbotenen Themen normalerweise darauf, wie intellektuell die Arbeit klingt, wenn sie in Forschungsarbeiten beschrieben wird, und nicht darauf, wie wichtig sie für gute Ergebnisse ist. Der Extremfall ist wahrscheinlich die Literatur; Leute, die Literatur studieren, sagen selten etwas, das für diejenigen, die sie produzieren, auch nur den geringsten Nutzen hätte.

Obwohl die Situation in den Naturwissenschaften besser ist, ist die Überschneidung zwischen der Art von Arbeit, die man machen darf, und der Art von Arbeit, die gute Sprachen hervorbringt, beunruhigend gering. (Olin Shivers hat sich eloquent darüber beschwert.) Typen scheinen beispielsweise eine unerschöpfliche Quelle für Forschungsarbeiten zu sein, obwohl die statische Typisierung echte Makros auszuschließen scheint – ohne die meiner Meinung nach keine Sprache es wert ist, verwendet zu werden.

Der Trend geht nicht nur dahin, dass Sprachen als Open-Source-Projekte und nicht als „Forschungsprojekte“ entwickelt werden, sondern dass Sprachen von den Anwendungsprogrammierern entwickelt werden, die sie verwenden müssen, und nicht von Compiler-Autoren. Das scheint ein guter Trend zu sein, und ich gehe davon aus, dass er sich fortsetzt.

Anders als die Physik in hundert Jahren, die sich fast zwangsläufig nicht vorhersagen lässt, halte ich es prinzipiell für möglich, jetzt eine Sprache zu entwickeln, die die Benutzer in hundert Jahren anspricht.

Eine Möglichkeit, eine Sprache zu entwerfen, besteht darin, einfach das Programm aufzuschreiben, das Sie schreiben möchten, unabhängig davon, ob es einen Compiler gibt, der es übersetzen kann, oder Hardware, die es ausführen kann. Wenn Sie dies tun, können Sie von unbegrenzten Ressourcen ausgehen. Es scheint, als könnten wir uns unbegrenzte Ressourcen heute genauso gut vorstellen wie in hundert Jahren.

Welches Programm möchte man schreiben? Was auch immer am wenigsten Arbeit macht. Aber nicht ganz: was auch immer am wenigsten Arbeit wäre , wenn Ihre Vorstellungen vom Programmieren nicht bereits von den Sprachen beeinflusst wären, an die Sie derzeit gewöhnt sind. Ein solcher Einfluss kann so durchdringend sein, dass es große Anstrengungen erfordert, ihn zu überwinden. Man sollte meinen, es wäre für so faule Wesen wie uns offensichtlich, wie man ein Programm mit möglichst geringem Aufwand ausdrückt. Tatsächlich sind unsere Vorstellungen davon, was möglich ist, tendenziell so sehr durch die Sprache eingeschränkt , in der wir denken, dass einfachere Formulierungen von Programmen sehr überraschend erscheinen. Sie sind etwas, das Sie entdecken müssen, nicht etwas, in das Sie von Natur aus hineinwachsen.

Ein hilfreicher Trick besteht hier darin, die Länge des Programms als Annäherungswert für den Arbeitsaufwand beim Schreiben zu verwenden. Natürlich nicht die Länge in Zeichen, sondern die Länge in einzelnen syntaktischen Elementen – im Grunde die Größe des Parsebaums. Es mag nicht ganz stimmen, dass das kürzeste Programm den geringsten Arbeitsaufwand erfordert, aber es ist nahe genug dran, dass Sie besser dran sind, wenn Sie das klare Ziel der Kürze anstreben, als das unscharfe, nahe gelegene Ziel des geringsten Arbeitsaufwands. Dann lautet der Algorithmus für die Sprachgestaltung: Sehen Sie sich ein Programm an und fragen Sie, ob es eine Möglichkeit gibt, es kürzer zu schreiben.

In der Praxis wird das Schreiben von Programmen in einer imaginären hundertjährigen Sprache in unterschiedlichem Maße funktionieren, je nachdem, wie nah Sie am Kern sind. Sortierroutinen können Sie jetzt schreiben. Aber es wäre heute schwer vorherzusagen, welche Arten von Bibliotheken in hundert Jahren benötigt werden könnten. Vermutlich werden viele Bibliotheken für Bereiche bestimmt sein, die noch gar nicht existieren. Wenn SETI@home beispielsweise funktioniert, werden wir Bibliotheken für die Kommunikation mit Außerirdischen benötigen. Es sei denn natürlich, sie sind so weit fortgeschritten, dass sie bereits in XML kommunizieren.

Am anderen Ende des Spektrums denke ich, dass man die Kernsprache heute noch entwickeln könnte. Manche würden sogar behaupten, dass sie größtenteils schon 1958 entwickelt wurde.

Wenn die hundertjährige Sprache heute verfügbar wäre, würden wir dann in ihr programmieren wollen? Eine Möglichkeit, diese Frage zu beantworten, besteht darin, zurückzublicken. Wenn die heutigen Programmiersprachen 1960 verfügbar gewesen wären, hätte irgendjemand sie verwenden wollen?

In gewisser Weise ist die Antwort nein. Heutige Sprachen setzen eine Infrastruktur voraus, die es 1960 noch nicht gab. Eine Sprache wie Python, in der Einrückungen eine wichtige Rolle spielen, würde beispielsweise auf Druckerterminals nicht sehr gut funktionieren. Aber wenn man solche Probleme einmal beiseite lässt – wenn man beispielsweise davon ausgeht, dass alle Programme nur auf Papier geschrieben wurden – hätten Programmierer in den 1960er Jahren gern Programme in den Sprachen geschrieben, die wir heute verwenden?

Ich denke schon. Einige der weniger einfallsreichen Programmierer, die Artefakte früherer Sprachen in ihre Vorstellungen von Programmen eingebaut hatten, hätten vielleicht Probleme gehabt. (Wie kann man Daten manipulieren, ohne Zeigerarithmetik durchzuführen? Wie kann man Flussdiagramme ohne Gotos implementieren?) Aber ich denke, die intelligentesten Programmierer hätten keine Probleme gehabt, das Beste aus den heutigen Sprachen herauszuholen, wenn sie sie gehabt hätten.

Wenn wir die hundertjährige Sprache jetzt hätten, wäre sie zumindest ein toller Pseudocode. Wie wäre es, sie zum Schreiben von Software zu verwenden? Da die hundertjährige Sprache für einige Anwendungen schnellen Code generieren muss, könnte sie vermutlich Code generieren, der effizient genug ist, um auf unserer Hardware akzeptabel gut zu laufen. Wir müssen in hundert Jahren vielleicht mehr Optimierungsratschläge geben als Benutzer, aber unter dem Strich könnte es dennoch ein Gewinn sein.

Nun haben wir zwei Ideen, die, wenn man sie kombiniert, interessante Möglichkeiten eröffnen: (1) Die Jahrhundertsprache könnte im Prinzip heute entwickelt werden, und (2) eine solche Sprache, falls sie existiert, könnte heute gut programmierbar sein. Wenn man diese Ideen so präsentiert sieht, ist es schwer, nicht zu denken: Warum nicht jetzt versuchen, die Jahrhundertsprache zu schreiben?

Ich denke, es ist gut, wenn man an der Sprachgestaltung arbeitet, ein solches Ziel zu haben und es bewusst im Auge zu behalten. Wenn man Autofahren lernt, ist eines der Prinzipien, das man lernt, das Auto nicht auszurichten, indem man die Motorhaube an den aufgemalten Streifen der Straße ausrichtet, sondern indem man auf einen Punkt in der Ferne zielt. Selbst wenn es einem nur darum geht, was in den nächsten drei Metern passiert, ist das die richtige Antwort. Ich denke, wir können und sollten dasselbe mit Programmiersprachen tun.

Hinweise

Ich glaube, dass Lisp Machine Lisp die erste Sprache war, die das Prinzip verkörperte, dass Deklarationen (außer denen dynamischer Variablen) lediglich Optimierungsratschläge waren und die Bedeutung eines korrekten Programms nicht änderten. Common Lisp scheint die erste Sprache gewesen zu sein, die dies explizit zum Ausdruck brachte.

Vielen Dank an Trevor Blackwell, Robert Morris und Dan Giffin für das Lesen der Entwürfe und an Guido van Rossum, Jeremy Hylton und den Rest der Python-Crew für die Einladung, bei PyCon zu sprechen.