Die Diskussion um Systemd als Ablösung von Sys-V-Init war für mich der erste große Kampf zwischen denen, die gern die Welt so erhalten wollen, wie sie sie kennen, und dem natürlichen Fortschritt. Vielleicht ist es mir damals auch so deutlich geworden, weil wir in der ersten Datenkanal-Folge zu Systemd genau diesen Konflikt hatten, aber erlebt hatte ich solche Streitigkeiten bei Umbrüchen schon zuvor: Beim Wechsel vom statischen /dev zu devfs gab es große Diskussionen über den neuen Weg und beim Wechsel zu Gnome-Shell bzw. Ubuntu Unity kam es zu Abspaltungen von Distributionen, die das alte System erhalten wollten – Gleiches geschah auch bei Systemd.
Ich glaube, in einer der Folgen des Datenkanals hatte ich die Prognose gewagt, dass das nächste solche Spektakel mit dem Wechsel vom X-Window-System zu Wayland kommen wird. Aber so lange hat es nicht gebraucht, die nächste Schlacht hat an einer anderen Front begonnen: im Linux-Kernel. Dort gibt es seit 2020 das Bestreben, Rust als Programmiersprache für Kernel-Code einzusetzen. Die Anfänge sind noch vage, aber Linus Trovalds steht der Idee nicht so ablehnend gegenüber wie der von C++ für den Kernel.
Obwohl noch gar nicht entschieden ist, ob diese Idee umsetzbar ist oder wie sie umgesetzt wird, gibt es schon riesige Diskussionen darum, ob man den Schritt der Veränderung gehen sollte oder nicht.
- Supporting Linux kernel development in Rust [LWN.net] (31. Aug. 2020)
- Rust support hits linux-next [LWN.net] (19. März 2021)
- Rust in the Linux kernel (Google security blog) [LWN.net] (15. April 2021)
- Rust heads into the kernel? [LWN.net] (21. April 2021)
Die Argumentation verläuft dann auf der Ebene von »aber das ist eine andere Syntax« und »die Code-Dokumentation in Rust sieht anders aus«, »dann braucht man ja einen weiteren/anderen Compiler« und »wenn ich dann etwas am Code ändern will, muss ich ja Rust können« und so weiter und so fort.
Einerseits merkt man, dass viele gekränkte C++-Freunde jetzt aufspringen und sich ungerecht behandelt fühlen, weil einer anderen Programmiersprache als ihrer der Vorzug gewährt wurde. Gegen solche gekränkten Gefühle kann man nur schwer ankommen und es lohnt nicht der Worte, wenn es um emotionale, statt sachlicher Fragen geht. Und andererseits springen hier wieder viele Leute auf – analog zur Diskussion mit Systemd –, die nicht akzeptieren können, dass es einen Wandel gibt und dass die Welt nicht so bleibt, wie sie sie kennen und beherrschen.
In dieser Gemengelage ist es dann noch schwieriger, die migrationsbedingten Reibungsverluste zu akzeptieren – die dann liebend gern als Argument gegen den Wandel verwendet werden. Bei jeder sanften Umstellung muss man zusätzliche Brücken bauen, die zu gehen eine Zeit lang unbequem ist, weil sie Alt und Neu miteinander verbinden, die doch so viel voneinander unterscheidet. Für Rust wird man viel Code schreiben müssen, um C- und Rust-Strukturen verbinden zu können. Genauso wie bei Systemd viele Helferlein im Hintergrund werkeln und die alten Konfigurationen von Cron oder Sys-V-Init in Systemd-Konfigurationen umwandeln. Aber anders geht es nicht bzw. der Weg des harten Umstiegs ist meist zu gefährlich und zu aufwändig.
Weil man mit dem Wechsel auch Neuland betritt, wird es zu Fehlern – auch schwerwiegenden – kommen. Bei Systemd wurde jeder Bug von den Welterhaltern exzessiv diskutiert und als Versagen der neuen Strategie zelebriert. Ich bin wahrlich kein Freund davon, jedem Schwein hinterher zu rennen, das durchs Dorf getrieben wird. Aber man muss sich Neuerung ansehen und anhand deren Konzepten und Zielen entscheiden, ob sie eine echte Neuerung bringen oder nur das Vorhandene fortführen, nur eben in gelb statt grün.
Rust ist eine neue Welt
Womit wir bei meiner zweiten Fehlprognose sind: In einer der Folgen zu Rust habe ich die Einschätzung getroffen, dass Rust sich eine weitere Programmiersprache zur Systementwicklung etablieren wird, aber nicht viel am Gesamtgefüge verändern wird. Mittlerweile bin ich durch meine Erfahrungen mit Rust aber anderer Meinung. Rust wird C und C++ Anteile abnehmen und auf lange Sicht wahrscheinlich auch die Vorherrschaft übernehmen.
C ist immer noch geprägt von den Umständen seiner Entstehungszeit und es ist leider so, dass man ganz schwer alte Zöpfe abschneiden kann. Der gewaltige Unterschied zwischen Rust und C ist der Informationsgehalt, den der Programmierer in den Quelltext packen muss. Durch Rusts strengere Speicherverwaltung, die erzwingt, dass nur höchstens ein schreibbarer Zugriff auf eine Speicherstelle existiert, muss der Programmierer den Quelltext anders strukturieren und liefert dem Compiler wesentlich mehr Informationen über seine Gedanken und Absichten als er es in C oder C++ tut.
Dieses Wissen um Gültigkeitsbereiche für Lese- und Schreibzugriffe fehlt einfach im Quelltext von C und kann vom Compiler nur erahnt werden. Somit bleiben dem C‑Compiler nicht die Möglichkeiten für Optimierungen und Gültigkeitsprüfungen wie in Rust. In einer der Diskussion kam der Vorschlag, man könne diese Informationen auch in C einbauen, aber dies würde die Programmierweise und den Charakter der Programmiersprache völlig verändern. Hier ist der Neuanfang wirklich besser. Ebenso greift auch das Argument nicht, dass man in C++ ähnliche Informationen mit den Smart-Pointern einpflegen kann – jedoch sind und bleiben diese weiterhin optional und werden nicht vom Compiler erzwungen.
Einen anderen – gefühlten – Quantensprung hat Rust mit dem Werkzeugen rund um die Programmiersprache hingelegt. C stammt aus einer Zeit, als Quelltext per Diskette verschickt oder über das UUCP-Netzwerk verbreitet wurde und Computer wenig Speicher und Rechenleistung besaßen … und dieser Charakter haftet C immer noch an. Angefangen von Werkzeugen wie autotools und configure, die versuchen, die Programme gemäß der vorhandenen Umgebung zu übersetzen, bis hin zu Sprachkonstrukten wie #include, die keine echte Modularisierung ermöglichen.
Rust kann heute den Zugriff auf das Internet voraussetzen und somit die passenden Bibliotheksversionen laden, die es benötigt. Den Eiertanz, den man mit configure und (im besten Fall) apt vollführen muss, um überhaupt ein Projekt kompilierfähig zu bekommen, ist mit cargo passé. In der Cargo.toml kann man beliebige Quellen (auch außerhalb des Zentralservers) angeben, von denen cargo die benötigten Crates besorgt – ein komplett anderer Ansatz als configure.
Auch bei den Fehlermeldungen hat Rust eine neue Ebene erklommen: Bei vielen Fehlern, die der Compiler entdeckt, ist recht sicher, was der Programmierer meinte. Aber anstatt diesen erratenen Zustand einfach anzunehmen, wird dem Programmierer gezielt der Vorschlag unterbreitet, wie er seinen Quelltext anpassen kann. Mit dem Programm cargo-fix lassen sich solche Vorschläge auch automatisch umsetzen, aber es bleibt ein bewusster Schritt, den der Programmierer gehen muss, und am Ende steht im Quellcode was gewollt ist und wird nicht immer implizit angenommen.
Der nächste Schritt sind dann Werkzeuge wie cargo-clippy und cargo-test, die zum einen den Quellcode auf typische Fehler analysieren und entsprechende Verbesserungsvorschläge anbieten1 und zum anderen den Programmierer das Erstellen und Ausführen von Software-Tests wahnsinnig erleichtern. Diese Idee der Software-Tests hat sich erst mit den Skriptsprachen und Duck-Typing wirklich durchgesetzt und daher fehlen in C die dafür notwendigen Strukturen. Dies ist genau der Ausdruck des Fortschreitens der Entwicklung.
-
etwas, das mit C in diesem Umfang nicht möglich ist, weil fast jede Anweisung korrekt ist – man denke an
if (var = NULL)
– und weil erst in den letzten 10 Jahren die Computer so leistungsfähig geworden sind, um solche Analysen durchzuführen ↩
Rust hat in mehrerlei Hinsicht Neuland betreten und wird noch mehr Veränderungen1 mit sich bringen. Und gerade darum, weil Rust neue Konzepte umsetzt und neue Ziele verfolgt, sehe ich in Rust das Potential zur Verschiebung im Gefüge der Programmiersprachen.
-
ein heißes Thema sind Shared-Libraries ↩