Loading...

DIE HUNDERTJÄHRIGE SPRACHE

Original

April 2003

(Dieser Aufsatz stammt aus einem Hauptvortrag auf PyCon 2003.)

Es ist schwer vorherzusagen, wie das Leben in hundert Jahren sein wird. Es gibt nur wenige Dinge, die wir mit Sicherheit sagen können. Wir wissen, dass jeder fliegende Autos fahren wird, dass die Zonierungsgesetze gelockert werden, um Gebäude mit Hunderten von Stockwerken zu ermöglichen, dass es die meiste Zeit dunkel sein wird und dass alle Frauen in den Kampfkünsten ausgebildet sein werden. Hier möchte ich mich auf ein Detail dieses Bildes konzentrieren. Welche Art von Programmiersprache werden sie verwenden, um die Software zu schreiben, die diese fliegenden Autos steuert?

Es ist wert, darüber nachzudenken, nicht so sehr, weil wir tatsächlich diese Sprachen verwenden werden, sondern weil wir, wenn wir Glück haben, Sprachen auf dem Weg von diesem Punkt zu jenem verwenden werden.

Ich denke, dass Sprachen, wie Arten, evolutionäre Bäume bilden werden, mit Sackgassen, die überall abzweigen. Wir können dies bereits beobachten. Cobol, trotz seiner gelegentlichen Beliebtheit, scheint keine intellektuellen Nachkommen zu haben. Es ist eine evolutionäre Sackgasse – eine Neandertaler-Sprache.

Ich sage ein ähnliches Schicksal für Java voraus. Manchmal schicken mir Leute Mails und sagen: „Wie kannst du sagen, dass Java sich nicht als erfolgreiche Sprache herausstellen wird? Es ist bereits eine erfolgreiche Sprache.“ Und ich gebe zu, dass es das ist, wenn man den Erfolg an dem Platz misst, den Bücher darüber einnehmen (insbesondere individuelle Bücher darüber), oder an der Anzahl der Studenten, die glauben, dass sie es lernen müssen, um einen Job zu bekommen. Wenn ich sage, dass Java sich nicht als erfolgreiche Sprache herausstellen wird, meine ich etwas Spezifischeres: dass Java sich als evolutionäre Sackgasse herausstellen wird, wie Cobol.

Das ist nur eine Vermutung. Ich könnte mich irren. Mein Punkt hier ist nicht, Java zu diskreditieren, sondern die Frage nach evolutionären Bäumen aufzuwerfen und die Leute zu fragen, wo auf dem Baum Sprache X steht. Der Grund, diese Frage zu stellen, ist nicht nur, damit unsere Geister in hundert Jahren sagen können: „Ich habe es euch gesagt.“ Es liegt daran, dass es eine nützliche Heuristik ist, um Sprachen zu finden, die jetzt gut zu programmieren sind, wenn man nah an den Hauptästen bleibt.

Zu jedem Zeitpunkt bist du wahrscheinlich am glücklichsten auf den Hauptästen eines evolutionären Baumes. Selbst als es noch viele Neandertaler gab, muss es schrecklich gewesen sein, einer zu sein. Die Cro-Magnons wären ständig gekommen, um dich zu verprügeln und dir dein Essen zu stehlen.

Der Grund, warum ich wissen möchte, wie Sprachen in hundert Jahren sein werden, ist, dass ich wissen möchte, auf welchen Ast des Baumes ich jetzt setzen soll.

Die Evolution von Sprachen unterscheidet sich von der Evolution von Arten, weil Äste konvergieren können. Der Fortran-Ast scheint sich beispielsweise mit den Nachkommen von Algol zu vereinen. Theoretisch ist dies auch für Arten möglich, aber es ist unwahrscheinlich, dass es bei größeren als einer Zelle passiert ist.

Konvergenz ist für Sprachen wahrscheinlicher, partly weil der Raum der Möglichkeiten kleiner ist, und partly weil Mutationen nicht zufällig sind. Sprachdesigner integrieren absichtlich Ideen aus anderen Sprachen.

Es ist besonders nützlich für Sprachdesigner, darüber nachzudenken, wohin die Evolution der Programmiersprachen wahrscheinlich führen wird, weil sie entsprechend steuern können. In diesem Fall wird „auf einem Hauptast bleiben“ mehr als nur eine Möglichkeit, eine gute Sprache auszuwählen. Es wird zu einer Heuristik, um die richtigen Entscheidungen über das Sprachdesign zu treffen.

Jede Programmiersprache kann in zwei Teile unterteilt werden: eine Menge grundlegender Operatoren, die die Rolle von Axiomen spielen, und den Rest der Sprache, der prinzipiell in Bezug auf diese grundlegenden Operatoren geschrieben werden könnte.

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

Ich denke, es ist wichtig, dass die Axiome nicht nur gut gewählt sind, sondern dass es wenige von ihnen gibt. Mathematiker haben sich immer so über Axiome gefühlt – je weniger, desto besser – und ich denke, sie haben recht.

Mindestens muss es eine nützliche Übung sein, den Kern einer Sprache genau zu betrachten, um zu sehen, ob es Axiome gibt, die beseitigt werden könnten. Ich habe in meiner langen Karriere als Schluffi festgestellt, dass Unordnung Unordnung züchtet, und ich habe gesehen, dass dies in Software ebenso geschieht wie unter Betten und in den Ecken von Räumen.

Ich habe das Gefühl, dass die Hauptäste des evolutionären Baumes durch die Sprachen verlaufen, die die kleinsten, saubersten Kerne haben. Je mehr du in einer Sprache selbst schreiben kannst, desto besser.

Natürlich mache ich eine große Annahme, wenn ich frage, wie Programmiersprachen in hundert Jahren sein werden. Werden wir in hundert Jahren überhaupt noch Programme schreiben? Werden wir den Computern nicht einfach sagen, was wir wollen, dass sie tun?

Bisher gab es in diesem Bereich nicht viel Fortschritt. Ich schätze, dass die Menschen in hundert Jahren immer noch den Computern sagen werden, was sie tun sollen, indem sie Programme verwenden, die wir als solche erkennen würden. Es mag Aufgaben geben, die wir jetzt durch das Schreiben von Programmen lösen und für die man in hundert Jahren keine Programme mehr schreiben muss, aber ich denke, es wird immer noch eine Menge Programmierung in der Art geben, die wir heute tun.

Es mag anmaßend erscheinen zu denken, dass irgendjemand vorhersagen kann, wie eine Technologie in hundert Jahren aussehen wird. Aber denk daran, dass wir bereits fast fünfzig Jahre Geschichte hinter uns haben. In die Zukunft zu blicken, ist eine fassbare Idee, wenn wir berücksichtigen, wie langsam sich Sprachen in den letzten fünfzig Jahren entwickelt haben.

Sprachen entwickeln sich langsam, weil sie nicht wirklich Technologien sind. Sprachen sind Notationen. Ein Programm ist eine formale Beschreibung des Problems, das du möchtest, dass ein Computer für dich löst. Daher ist die Evolutionsrate in Programmiersprachen eher mit der Evolutionsrate in mathematischen Notationen vergleichbar als mit Transport oder Kommunikation. Mathematische Notation entwickelt sich, aber nicht mit den riesigen Sprüngen, die man in der Technologie sieht.

Was auch immer Computer in hundert Jahren ausmachen wird, es scheint sicher vorherzusagen, dass sie viel schneller sein werden als jetzt. Wenn das Mooresche Gesetz weiterhin gilt, werden sie 74 Quintillionen (73.786.976.294.838.206.464) Mal schneller sein. Das ist schwer vorstellbar. Und in der Tat könnte die wahrscheinlichste Vorhersage im Geschwindigkeitsbereich sein, dass das Mooresche Gesetz aufhören wird zu funktionieren. Alles, was alle achtzehn Monate verdoppelt werden soll, scheint irgendwann gegen eine Art von grundlegender Grenze zu stoßen. Aber ich habe keine Schwierigkeiten zu glauben, dass Computer viel schneller sein werden. Selbst wenn sie nur eine lächerliche Million Mal schneller werden, sollte das die Spielregeln für Programmiersprachen erheblich ändern. Unter anderem wird es mehr Raum für das geben, was jetzt als langsame Sprachen betrachtet wird, was bedeutet, dass Sprachen, die keinen sehr effizienten Code erzeugen.

Und doch werden einige Anwendungen weiterhin Geschwindigkeit verlangen. Einige der Probleme, die wir mit Computern lösen wollen, werden von Computern erzeugt; zum Beispiel hängt die Geschwindigkeit, mit der du Video-Bilder verarbeiten musst, von der Geschwindigkeit ab, mit der ein anderer Computer sie erzeugen kann. Und es gibt eine andere Klasse von Problemen, die von Natur aus eine unbegrenzte Kapazität haben, Zyklen zu absorbieren: Bildrendering, Kryptographie, Simulationen.

Wenn einige Anwendungen zunehmend ineffizient sein können, während andere weiterhin die gesamte Geschwindigkeit verlangen, die die Hardware liefern kann, werden schnellere Computer bedeuten, dass Sprachen ein immer breiteres Spektrum an Effizienzen abdecken müssen. Wir haben dies bereits beobachtet. Aktuelle Implementierungen einiger beliebter neuer Sprachen sind schockierend verschwenderisch im Vergleich zu den Standards der vorherigen Jahrzehnte.

Das ist nicht nur etwas, das mit Programmiersprachen passiert. Es ist ein allgemeiner historischer Trend. Wenn Technologien sich verbessern, kann jede Generation Dinge tun, die die vorherige Generation als verschwenderisch angesehen hätte. Die Menschen vor dreißig Jahren wären erstaunt darüber, wie lässig wir Ferngespräche führen. Die Menschen vor hundert Jahren wären noch erstaunter darüber, dass ein Paket eines Tages von Boston nach New York über Memphis reisen würde.

Ich kann dir bereits sagen, was mit all diesen zusätzlichen Zyklen passieren wird, die uns die schnellere Hardware in den nächsten hundert Jahren geben wird. Sie werden fast alle verschwendet werden.

Ich habe das Programmieren gelernt, als Computerleistung knapp war. Ich kann mich erinnern, dass ich alle Leerzeichen 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 verbrennt, um immer wieder dasselbe zu tun, erscheint mir irgendwie ekelhaft. Aber ich denke, meine Intuitionen hier sind falsch. Ich bin wie jemand, der arm aufgewachsen ist und es nicht ertragen kann, Geld auszugeben, selbst für etwas Wichtiges, wie zum Arzt zu gehen.

Einige Arten von Verschwendung sind wirklich ekelhaft. SUVs wären zum Beispiel auch dann ekelhaft, wenn sie mit einem Kraftstoff betrieben würden, der niemals ausgeht und keine Verschmutzung erzeugt. 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, wo wir die Infrastruktur haben, um sie zu unterstützen, beginnt es, kleinlich zu erscheinen, die Minuten deiner Ferngespräche zu zählen. Wenn du die Ressourcen hast, ist es eleganter, alle Telefonate als eine Art von Dingen zu betrachten, egal wo sich die andere Person befindet.

Es gibt gute Verschwendung und schlechte Verschwendung. Ich interessiere mich für gute Verschwendung – die Art, bei der wir durch mehr Ausgaben einfachere Designs erhalten können. Wie werden wir die Möglichkeiten nutzen, Zyklen zu verschwenden, die wir durch neue, schnellere Hardware erhalten?

Der Wunsch nach Geschwindigkeit ist so tief in uns verwurzelt, mit unseren mickrigen Computern, dass es bewusste Anstrengungen erfordern wird, ihn zu überwinden. Im Sprachdesign sollten wir bewusst nach Situationen suchen, in denen wir Effizienz gegen auch nur den kleinsten Anstieg an Bequemlichkeit eintauschen können.

Die meisten Datenstrukturen existieren wegen der Geschwindigkeit. Viele Sprachen haben heute sowohl Strings als auch Listen. Semantisch sind Strings mehr oder weniger eine Teilmenge von Listen, in denen die Elemente Zeichen sind. Warum brauchst du also einen separaten Datentyp? Du brauchst ihn wirklich nicht. Strings existieren nur aus Effizienzgründen. Aber es ist lahm, die Semantik der Sprache mit Hacks zu überladen, um Programme schneller auszuführen. Strings in einer Sprache zu haben, scheint ein Fall von verfrühter Optimierung zu sein.

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

Der richtige Weg, dieses Problem zu lösen, besteht, denke ich, darin, die Bedeutung eines Programms von den Implementierungsdetails zu trennen. Anstatt sowohl Listen als auch Strings zu haben, sollte es nur Listen geben, mit einer Möglichkeit, dem Compiler Optimierungsanweisungen zu geben, die es ihm ermöglichen, Strings bei Bedarf als zusammenhängende Bytes anzuordnen.

Da Geschwindigkeit in den meisten Teilen eines Programms keine Rolle spielt, musst du dich normalerweise nicht mit dieser Art von Mikromanagement beschäftigen. Das wird immer mehr zutreffen, je schneller die Computer werden.

Weniger über die Implementierung zu sagen, sollte auch die Programme flexibler machen. Spezifikationen ändern sich, während ein Programm geschrieben wird, und das ist nicht nur unvermeidlich, sondern wünschenswert.

Das Wort „Aufsatz“ stammt vom französischen Verb „essayer“, was „versuchen“ bedeutet. Ein Aufsatz, im ursprünglichen Sinne, ist etwas, das du schreibst, um zu versuchen, etwas herauszufinden. Das passiert auch in der Software. Ich denke, einige der besten Programme waren Aufsätze, in dem Sinne, dass die Autoren zu Beginn nicht genau wussten, was sie zu schreiben versuchten.

Lisp-Hacker wissen bereits um den Wert, mit Datenstrukturen flexibel zu sein. Wir neigen dazu, die erste Version eines Programms so zu schreiben, dass sie alles mit Listen macht. Diese ersten Versionen können so schockierend ineffizient sein, dass es eine bewusste Anstrengung erfordert, nicht darüber nachzudenken, was sie tun, so wie es für mich zumindest eine bewusste Anstrengung erfordert, nicht darüber nachzudenken, woher ein Steak kommt, während ich es esse.

Wonach Programmierer in hundert Jahren vor allem suchen werden, ist eine Sprache, in der man eine unglaublich ineffiziente Version 1 eines Programms mit dem geringstmöglichen Aufwand zusammenstellen kann. Zumindest so würden wir es in der heutigen Sprache beschreiben. Was sie sagen werden, ist, dass sie eine Sprache wollen, die einfach zu programmieren ist.

Ineffiziente Software ist nicht ekelhaft. Ekelhaft ist eine Sprache, die Programmierer unnötige Arbeit machen lässt. Die wahre Ineffizienz besteht darin, die Zeit der Programmierer zu verschwenden, nicht die Maschinenzeit. Das wird immer klarer werden, je schneller die Computer werden.

Ich denke, dass es bereits etwas ist, worüber wir nachdenken könnten, Strings loszuwerden. Wir haben es in Arc getan, und es scheint ein Gewinn zu sein; einige Operationen, die umständlich als reguläre Ausdrücke beschrieben werden könnten, können leicht als rekursive Funktionen beschrieben werden.

Wie weit wird diese Vereinheitlichung von Datenstrukturen gehen? Ich kann an Möglichkeiten denken, die selbst mich mit meinem gewissenhaft erweiterten Geist schockieren. Werden wir zum Beispiel Arrays loswerden? Schließlich sind sie nur eine Teilmenge von Hash-Tabellen, bei denen die Schlüssel Vektoren von Ganzzahlen sind. Werden wir Hash-Tabellen selbst durch Listen ersetzen?

Es gibt noch schockierendere Aussichten als das. Der Lisp, den McCarthy 1960 beschrieb, hatte zum Beispiel keine Zahlen. Logisch gesehen brauchst du kein separates Konzept von Zahlen, weil du sie als Listen darstellen kannst: Die ganze Zahl n könnte als Liste von n Elementen dargestellt werden. Du kannst auf diese Weise rechnen. Es ist nur unerträglich ineffizient.

Niemand hat tatsächlich vorgeschlagen, Zahlen in der Praxis als Listen zu implementieren. Tatsächlich war McCarthys Papier von 1960 zu diesem Zeitpunkt nicht zur Implementierung gedacht. Es war eine theoretische Übung, ein Versuch, eine elegantere Alternative zur Turing-Maschine zu schaffen. Als jemand unerwartet dieses Papier nahm und es in einen funktionierenden Lisp-Interpreter übersetzte, wurden Zahlen sicherlich nicht als Listen dargestellt; sie wurden in binär dargestellt, wie in jeder anderen Sprache.

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

Um das klarzustellen, ich schlage nicht vor, dass alle numerischen Berechnungen tatsächlich mit Listen durchgeführt werden. Ich schlage vor, dass die Kernsprache, vor jeglichen zusätzlichen Notationen über die Implementierung, auf diese Weise definiert wird. In der Praxis würde jedes Programm, das eine gewisse Menge an Mathematik durchführen wollte, wahrscheinlich Zahlen in binär darstellen, aber das wäre eine Optimierung, nicht Teil der Semantik der Kernsprache.

Eine andere Möglichkeit, Zyklen zu verbrennen, besteht darin, viele Schichten von Software zwischen der Anwendung und der Hardware zu haben. Auch dies ist ein Trend, den wir bereits beobachten: Viele neuere Sprachen werden in Bytecode kompiliert. Bill Woods sagte mir einmal, dass als Faustregel jede Schicht der Interpretation einen Geschwindigkeitsfaktor von 10 kostet. Diese zusätzlichen Kosten kaufen dir Flexibilität.

Die allererste Version von Arc war ein extremes Beispiel für diese Art von mehrschichtiger Langsamkeit, mit entsprechenden Vorteilen. Es war ein klassischer „metazirkulärer“ Interpreter, der auf Common Lisp geschrieben wurde, mit einer deutlichen familiären Ähnlichkeit zur eval-Funktion, die in McCarthys ursprünglichem Lisp-Papier definiert wurde. Das Ganze bestand nur aus ein paar hundert Zeilen Code, sodass es sehr einfach zu verstehen und zu ändern war. Das Common Lisp, das wir verwendeten, CLisp, läuft selbst auf einem Bytecode-Interpreter. Hier hatten wir also zwei Ebenen der Interpretation, von denen eine (die oberste) schockierend ineffizient war, und die Sprache war benutzbar. Kaum benutzbar, gebe ich zu, aber benutzbar.

Software in mehreren Schichten zu schreiben, ist eine leistungsstarke Technik, selbst innerhalb von Anwendungen. Bottom-up-Programmierung bedeutet, ein Programm als eine 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 zu diesem heiligen Gral, der Wiederverwendbarkeit. Eine Sprache ist definitionsgemäß wiederverwendbar. Je mehr du von deiner Anwendung in eine Sprache für das Schreiben dieser Art von Anwendung drücken kannst, desto mehr wird deine Software wiederverwendbar sein.

Irgendwie wurde die Idee der Wiederverwendbarkeit in den 1980er Jahren an die objektorientierte Programmierung angeheftet, und kein noch so überzeugender Beweis scheint sie davon abbringen zu können. Aber obwohl einige objektorientierte Software wiederverwendbar ist, ist es ihre Bottom-up-Natur, die sie wiederverwendbar macht, nicht ihre objektorientierte Natur. Betrachte Bibliotheken: Sie sind wiederverwendbar, weil sie Sprache sind, egal ob sie in einem objektorientierten Stil geschrieben sind oder nicht.

Ich sage übrigens nicht das Ende der objektorientierten Programmierung voraus. Obwohl ich nicht denke, dass sie viel für gute Programmierer zu bieten hat, außer in bestimmten spezialisierten Bereichen, ist sie für große Organisationen unwiderstehlich. Objektorientierte Programmierung bietet eine nachhaltige Möglichkeit, Spaghetti-Code zu schreiben. Sie lässt dich Programme als eine Reihe von Patches ansammeln.

Große Organisationen neigen immer dazu, Software auf diese Weise zu entwickeln, und ich erwarte, dass dies in hundert Jahren genauso wahr sein wird wie heute.

Solange wir über die Zukunft sprechen, sollten wir besser über parallele Berechnung sprechen, denn dort scheint diese Idee zu leben. Das heißt, egal wann du sprichst, parallele Berechnung scheint etwas zu sein, das in der Zukunft passieren wird.

Wird die Zukunft jemals mit ihr Schritt halten? Die Leute sprechen seit mindestens 20 Jahren über parallele Berechnung als etwas Imminentes, und es hat die Programmierpraxis bisher nicht viel beeinflusst. Oder etwa doch? Bereits Chip-Designer müssen darüber nachdenken, und auch die Leute, die versuchen, Systemsoftware auf Multi-CPU-Computern zu schreiben.

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

Eine Sache, die wahrscheinlich ist, ist, dass die meisten Möglichkeiten zur Parallelität verschwendet werden. Dies ist ein spezieller Fall meiner allgemeineren Vorhersage, dass die meisten der zusätzlichen Computerleistung, die uns gegeben wird, verschwendet wird. Ich erwarte, dass, wie bei der stupenden Geschwindigkeit der zugrunde liegenden Hardware, Parallelität etwas sein wird, das verfügbar ist, wenn du ausdrücklich danach fragst, aber normalerweise nicht genutzt wird. Das impliziert, dass die Art von Parallelität, die wir in hundert Jahren haben werden, nicht, außer in speziellen Anwendungen, massive Parallelität sein wird. Ich erwarte, dass es für gewöhnliche Programmierer eher so sein wird, als könnten sie Prozesse abspalten, die alle parallel laufen.

Und das wird, wie das Fragen nach spezifischen Implementierungen von Datenstrukturen, etwas sein, das du ziemlich spät im Leben eines Programms tust, wenn du versuchst, es zu optimieren. Version 1s werden normalerweise alle Vorteile ignorieren, die aus paralleler Berechnung gewonnen werden können, genau wie sie Vorteile ignorieren werden, die aus spezifischen Darstellungen von Daten gewonnen werden können.

Außer in speziellen Arten von Anwendungen wird Parallelität nicht die Programme durchdringen, die in hundert Jahren geschrieben werden. Es wäre verfrühte Optimierung, wenn dem so wäre.

Wie viele Programmiersprachen wird es in hundert Jahren geben? Es scheint in letzter Zeit eine riesige Anzahl neuer Programmiersprachen zu geben. Ein Teil des Grundes ist, dass schnellere Hardware es Programmierern ermöglicht hat, unterschiedliche Kompromisse zwischen Geschwindigkeit und Bequemlichkeit je nach Anwendung einzugehen. Wenn dies ein echter Trend ist, sollte die Hardware, die wir in hundert Jahren haben werden, ihn nur verstärken.

Und doch könnte es in hundert Jahren nur wenige weit verbreitete Sprachen geben. Ein Teil des Grundes, warum ich das sage, ist Optimismus: Es scheint, dass, wenn du wirklich gute Arbeit leistest, du eine Sprache schaffen könntest, die ideal für das Schreiben einer langsamen Version 1 ist, und doch mit den richtigen Optimierungsanweisungen an den Compiler auch sehr schnellen Code erzeugen würde, wenn nötig. Da ich optimistisch bin, werde ich vorhersagen, dass Programmierer in hundert Jahren trotz der riesigen Kluft zwischen akzeptabler und maximaler Effizienz Sprachen haben werden, die die meisten davon abdecken können.

Während sich diese Kluft vergrößert, werden Profiler immer wichtiger werden. Derzeit wird der Profilierung wenig Aufmerksamkeit geschenkt. Viele Menschen scheinen immer noch zu glauben, dass der Weg zu schnellen Anwendungen darin besteht, Compiler zu schreiben, die schnellen Code erzeugen. Je mehr sich die Kluft zwischen akzeptabler und maximaler Leistung vergrößert, desto klarer wird es, dass der Weg zu schnellen Anwendungen darin besteht, einen guten Leitfaden von einer zur anderen zu haben.

Wenn ich sage, dass es nur wenige Sprachen geben könnte, schließe ich nicht domänenspezifische „kleine Sprachen“ ein. Ich denke, solche eingebetteten Sprachen sind eine großartige Idee, und ich erwarte, dass sie sich verbreiten werden. Aber ich erwarte, dass sie als dünne genug Schalen geschrieben werden, damit die Benutzer die darunter liegende allgemeine Sprache sehen können.

Wer wird die Sprachen der Zukunft entwerfen? Einer der aufregendsten Trends in den letzten zehn Jahren war der Aufstieg von Open-Source-Sprachen wie Perl, Python und Ruby. Das Sprachdesign wird von Hackern übernommen. Die bisherigen Ergebnisse sind chaotisch, aber ermutigend. Es gibt einige erstaunlich neuartige Ideen in Perl, zum Beispiel. Viele sind erstaunlich schlecht, aber das ist immer der Fall bei ehrgeizigen Bemühungen. In der gegenwärtigen Mutationsrate, Gott weiß, was Perl in hundert Jahren werden könnte.

Es ist nicht wahr, dass die, die nicht können, lehren (einige der besten Hacker, die ich kenne, sind Professoren), aber es ist wahr, dass es viele Dinge gibt, die die, die lehren, nicht können. Forschung auferlegt einschränkende Kastenbeschränkungen. In jedem akademischen Bereich gibt es Themen, an denen es in Ordnung ist zu arbeiten, und andere, an denen es nicht in Ordnung 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; Menschen, die Literatur studieren, sagen selten etwas, das für diejenigen, die sie produzieren, von geringstem Nutzen wäre.

Obwohl die Situation in den Wissenschaften besser ist, ist die Überschneidung zwischen der Art von Arbeit, die du tun darfst, und der Art von Arbeit, die gute Sprachen hervorbringt, besorgniserregend klein. (Olin Shivers hat eloquent darüber geklagt.) Zum Beispiel scheinen Typen eine unerschöpfliche Quelle von Forschungsarbeiten zu sein, obwohl statische Typisierung anscheinend wahre Makros ausschließt – 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 „Forschung“ entwickelt werden, sondern auch dahin, dass Sprachen von den Anwendungsprogrammierern entworfen werden, die sie verwenden müssen, und nicht von Compiler-Autoren. Das scheint ein guter Trend zu sein, und ich erwarte, dass er anhält.

Im Gegensatz zur Physik in hundert Jahren, die fast zwangsläufig unmöglich vorherzusagen ist, denke ich, dass es prinzipiell möglich sein könnte, jetzt eine Sprache zu entwerfen, die in hundert Jahren für Benutzer ansprechend wäre.

Eine Möglichkeit, eine Sprache zu entwerfen, besteht darin, einfach das Programm aufzuschreiben, das du gerne schreiben würdest, unabhängig davon, ob es einen Compiler gibt, der es übersetzen kann, oder Hardware, die es ausführen kann. Wenn du das tust, kannst du unbegrenzte Ressourcen annehmen. Es scheint, als sollten wir uns unbegrenzte Ressourcen heute genauso gut vorstellen können wie in hundert Jahren.

Welches Programm würde man gerne schreiben? Was auch immer am wenigsten Arbeit ist. Außer nicht ganz: was am wenigsten Arbeit wäre, wenn deine Ideen über Programmierung nicht bereits von den Sprachen beeinflusst wären, an die du gewöhnt bist. Solcher Einfluss kann so durchdringend sein, dass es große Anstrengungen erfordert, ihn zu überwinden. Du würdest denken, es wäre offensichtlich für Kreaturen, die so faul sind wie wir, wie man ein Programm mit dem geringsten Aufwand ausdrückt. Tatsächlich sind unsere Ideen darüber, was möglich ist, so begrenzt durch die Sprache, in der wir denken, dass einfachere Formulierungen von Programmen sehr überraschend erscheinen. Sie sind etwas, das du entdecken musst, nicht etwas, in das du natürlich hineinsinkst.

Ein hilfreicher Trick hier ist, die Länge des Programms als Annäherung dafür zu verwenden, wie viel Arbeit es ist, es zu schreiben. Nicht die Länge in Zeichen, natürlich, sondern die Länge in unterschiedlichen syntaktischen Elementen – im Grunde die Größe des Parse-Baums. Es mag nicht ganz wahr sein, dass das kürzeste Programm das wenigste Arbeit erfordert, aber es ist nah genug, dass du besser darauf abzielst, das solide Ziel der Kürze zu erreichen, als das verschwommene, nahe Ziel des geringsten Aufwands. Dann wird der Algorithmus für das Sprachdesign: Schau dir ein Programm an und frage, ob es irgendeine Möglichkeit gibt, dies kürzer zu schreiben?

In der Praxis wird das Schreiben von Programmen in einer imaginären Hundertjahres-Sprache je nach Nähe zum Kern unterschiedlich gut funktionieren. Sortier-Routinen kannst du jetzt schreiben. Aber es wäre schwer vorherzusagen, welche Arten von Bibliotheken in hundert Jahren benötigt werden könnten. Vermutlich werden viele Bibliotheken für Bereiche sein, die noch nicht einmal existieren. Wenn SETI@home funktioniert, werden wir zum Beispiel Bibliotheken für die Kommunikation mit Aliens benötigen. Es sei denn, sie sind so weit fortgeschritten, dass sie bereits in XML kommunizieren.

Am anderen Ende denke ich, dass du die Kernsprache heute entwerfen könntest. Tatsächlich könnte man argumentieren, dass sie bereits 1958 größtenteils entworfen 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ückzuschauen. Wenn die heutigen Programmiersprachen 1960 verfügbar gewesen wären, hätte sie dann jemand verwenden wollen?

In gewisser Hinsicht ist die Antwort nein. Sprachen heute setzen eine Infrastruktur voraus, die 1960 nicht existierte. Zum Beispiel würde eine Sprache, in der Einrückungen bedeutend sind, wie Python, auf Drucker-Terminals nicht sehr gut funktionieren. Aber wenn man solche Probleme beiseite lässt – vorausgesetzt, dass Programme alle einfach auf Papier geschrieben wurden – hätten Programmierer der 1960er Jahre gerne in den Sprachen geschrieben, die wir jetzt verwenden?

Ich denke schon. Einige der weniger einfallsreichen, die Artefakte früherer Sprachen in ihre Vorstellungen davon, was ein Programm war, eingebaut hatten, hätten Schwierigkeiten gehabt. (Wie kannst du Daten manipulieren, ohne Zeigerarithmetik zu verwenden? Wie kannst du Flussdiagramme ohne Gotos implementieren?) Aber ich denke, die klügsten Programmierer hätten keine Schwierigkeiten gehabt, das Beste aus den heutigen Sprachen zu machen, wenn sie sie gehabt hätten.

Wenn wir jetzt die Hundertjährige Sprache hätten, wäre sie zumindest ein großartiger Pseudocode. Was ist mit der Verwendung, um Software zu schreiben? 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 zu laufen. Wir müssten vielleicht mehr Optimierungsanweisungen geben als Benutzer in hundert Jahren, aber es könnte immer noch ein Netto-Gewinn sein.

Jetzt haben wir zwei Ideen, die, wenn du sie kombinierst, interessante Möglichkeiten vorschlagen: (1) Die Hundertjährige Sprache könnte prinzipiell heute entworfen werden, und (2) eine solche Sprache, wenn sie existierte, könnte heute gut zu programmieren sein. Wenn du diese Ideen so siehst, ist es schwer, nicht zu denken: Warum nicht versuchen, die Hundertjährige Sprache jetzt zu schreiben?

Wenn du am Sprachdesign arbeitest, denke ich, dass es gut ist, ein solches Ziel zu haben und es bewusst im Hinterkopf zu behalten. Wenn du das Fahren lernst, ist eines der Prinzipien, die sie dir beibringen, das Auto nicht auszurichten, indem du die Motorhaube mit den auf der Straße gemalten Streifen ausrichtest, sondern indem du auf einen Punkt in der Ferne zielst. Selbst wenn dir nur wichtig ist, was in den nächsten zehn Fuß passiert, ist dies die richtige Antwort. Ich denke, wir können und sollten dasselbe mit Programmiersprachen tun.

Anmerkungen

Ich glaube, Lisp Machine Lisp war die erste Sprache, die das Prinzip verkörperte, dass Deklarationen (außer die von dynamischen Variablen) lediglich Optimierungsanweisungen waren und die Bedeutung eines korrekten Programms nicht ändern würden. Common Lisp scheint die erste zu sein, die dies ausdrücklich erklärt hat.

Danke an Trevor Blackwell, Robert Morris und Dan Giffin für das Lesen von Entwürfen davon und an Guido van Rossum, Jeremy Hylton und den Rest des Python-Teams für die Einladung, auf PyCon zu sprechen.