Rust oder Zig? Was der Rust‑zu‑Zig‑Rewrite des Roc‑Compilers über Sprachwahl und Migration lehrt
Einstieg: Ein realer Fall, eine konkrete Frage
Wenn Teams einen großen Rewrite erwägen, steht schnell die Sprachwahl im Raum: Bleiben wir bei Rust – oder wagen wir mit Zig einen Neuanfang? Ein aktueller, gut dokumentierter Praxisfall liefert Substanz jenseits von Bauchgefühl: Der Compiler der funktionalen Sprache Roc wird als Scratch‑Rewrite von Rust nach Zig migriert. Die Macher begründen das offen – inklusive technischer Trade‑offs, Build‑Erfahrung und Toolchain‑Überlegungen. Dieser Artikel fasst die belegten Motive zusammen und leitet Entscheidungshilfen für andere Teams ab.
Quellenbasis:
- Richard Feldmans Notiz zum geplanten Scratch‑Rewrite in Zig, inklusive Beweggründen und Compiler‑Roadmap (Gist).
- Offizielle FAQ von Roc zur Rolle von Zig und zur Nicht‑Self‑Hosting‑Strategie (Roc‑FAQ).
- Öffentliche Diskussionen und O‑Töne zum Fortschritt und zu praktischen Hürden (z. B. Lobsters‑Thread mit Antworten von Feldman: Lobsters).
- Gesprächsformate mit Projektbeteiligten (Zig SHOWTIME, Corrode‑Podcast).
Kontext und These
Der Roc‑Compiler bestand über Jahre aus mehreren hunderttausend Zeilen Rust. Parallel setzte Roc schon länger auf Zig in Teilen der Standardbibliothek – aus Gründen der Speicher‑ und Byte‑Level‑Kontrolle. Laut Feldman stand nun ohnehin eine weitreichende Überarbeitung nahezu aller Compilerphasen an. Statt viele Einzel‑Rewrites in Rust zu verteilen, entschied sich das Team für einen Neuanfang in Zig – mit dem Ziel, Build‑ und Iterationszeiten zu verbessern, den LLVM‑Pfad zu vereinfachen und bestimmte Low‑Level‑Optimierungen ergonomischer nutzbar zu machen. Die These: Die Wahl zwischen Rust und Zig ist keine Grundsatzfrage, sondern hängt stark von Projektzielen, Toolchain‑Bedarf und Team‑Workflow ab.
Kurzporträt des Fallbeispiels: Warum Roc relevant ist
Roc ist eine noch junge, performante, funktionale Sprache. Das Team kommuniziert offen, dass das Projekt nicht stabil ist und größere Umbauten einkalkuliert – ein wichtiger Rahmen für die Akzeptanz temporärer Regressionen. Aus der FAQ geht hervor: Roc will hohe Compiler‑Performance, bevorzugt statische Dispatch‑Wege und meidet Features, die Inferenz und Fehlermeldungen verwässern. Für den Host‑Compiler setzt das Projekt explizit auf eine Systemsprache und nicht auf Self‑Hosting in Roc selbst (begründet mit Performance‑ und Komplexitätszielen), was Zig als Kandidaten früh legitimierte (vgl. Roc‑FAQ).
Warum das Team umgeschwenkt ist: Motivationen aus Primärquellen
Aus Feldmans Notiz ergeben sich zwei Stränge: technische Kernmotive und organisatorische Überlegungen – beide aus der konkreten Roadmap abgeleitet.
Technische Kernmotive
- Build‑ und Iterationszeiten: Laut Feldman war die Compile‑Iteration in Rust ein spürbarer Produktivitätsdämpfer. Selbst kleine Änderungen führten zu Wartezeiten im zweistelligen Sekundenbereich – selbst in „schnellen“ Teilbäumen wie dem Parser. Zig wird hier als Hoffnungsträger gesehen, weil Recompile‑Schleifen am Zig‑Compiler selbst sehr kurz sein können. Explizit ergänzt Feldman aber, dass Zigs x86‑64‑Backend und das geplante inkrementelle Build‑System zum Zeitpunkt seiner Notiz noch nicht stabil sind. Diese Einordnung ist zentral: Der erwartete Vorteil betrifft vor allem die Richtung und das Entwicklungsmodell, nicht einen garantierten Ist‑Zustand.
- LLVM‑Anbindung über Bitcode: Wiederholte LLVM‑Upgrades via API galten als kostspielig. Zig umgeht das durch direkte Bitcode‑Erzeugung; die dafür nötige Logik im Zig‑Compiler ist MIT‑lizenziert und kann wiederverwendet werden (so Feldman). Das verspricht weniger Upgradekosten – und perspektivisch Caching‑Chancen auf Bitcode‑Ebene.
- Statische, portable Binaries: Das Team will seit Langem einfach statisch gelinkte Linux‑Binaries (musl), etwa für Container‑Umgebungen wie Alpine. Zig vereinfacht diesen Weg, inklusive des Buildens von LLVM gegen musl (Feldman: „genau das, was wir brauchen“). Möglich ist das auch in Rust, nach Teamangabe aber mit höherem Aufwand.
- Speicherverwaltung und Datenlayout: Der Roc‑Compiler arbeitet bereits allocator‑zentriert (Arena‑/Allocator‑Muster) und mit Datenorientierung (Struct‑of‑Arrays u. a.). Feldman erwartet hier in Zig pragmatischere Ergonomie, etwa durch Datentypen wie MultiArrayList und flexible Bit‑Feldstrukturen für kompaktes Metadaten‑Packing.
Organisatorische Motive
- „Ohnehin‑Rewrite“: Laut Feldman stand praktisch jede Phase außer der Typinferenz auf der Liste für grundlegende Umbauten – Parser, Formatter, Canonicalization/Name‑Resolution, Monomorphisierung, Codegen, Entwicklungs‑Backend. Statt viele parallele Großbaustellen im bestehenden Rust‑Code zu betreiben, bündelt das Team Aufwand und Wissenszuwachs in einer frischen, konsistenten Architektur.
- Gemeinsamer Sprachmix: Teile der Roc‑Stdlib waren schon zuvor in Zig implementiert. Der Wechsel des Compilers in dieselbe Richtung reduziert konzeptuelle Reibung im Projekt.
Technische Trade‑offs zwischen Rust und Zig – speziell für Compilerprojekte
Aus den Quellen lassen sich klare, aber kontextgebundene Abwägungen ableiten. Wichtig: Es geht nicht um „besser“ im Allgemeinen, sondern um Passung zu Zielbild und Team.
Build‑ und Iterationszeiten: Erwartung vs. Realität
Beobachtung im Projekt: Feldman schildert spürbar langsame Rebuilds im Rust‑Setup – selbst bei selektiven Änderungen. In Zig erwartet das Team kürzere Feedback‑Schleifen, verweist aber ausdrücklich darauf, dass zentrale Bausteine (x86‑64‑Backend, inkrementeller Build) zum Zeitpunkt der Entscheidung noch nicht stabil sind. Der Migrationsgrund ist also klar, die Stabilitätslage wird jedoch transparent benannt.
Speicherverwaltung und Safety
- Rusts Ownership bringt starke Garantien – mit Ergonomie‑Kosten, sobald man in datenorientierten, arena‑lastigen Strukturen Indexe statt Zeiger verwendet oder per FFI/Low‑Level‑Optimierungen arbeitet. Im Roc‑Compiler war „unsafe“ nach Feldmans Darstellung kein Ausnahmefall, u. a. für Indizes‑über‑Zeiger‑Muster und Caching.
- Zig setzt auf explizite Kontrolle via Allocators. Laut Feldman passen die Lebenszeiten im Roc‑Compiler gut zu diesem Modell, da Daten pro Pipeline‑Stufe isoliert sind (Strings werden früh interned, weitere Strukturen sind stufengebunden). Das Team sieht hier keine entscheidenden Safety‑Vorteile durch Rust – wohl aber Ergonomie‑Vorteile durch Zig für die eigene Arbeitsweise.
- Debug‑Checks in Zig: Feldman berichtet, dass Zig in Debug‑Builds mit zusätzlichem Runtime‑Bookkeeping viele Speicherfehler früh sichtbar macht. Formuliert als Projekterfahrung: Laut Feldman können in Debug‑Builds u. a. Double‑Free und manche Leak‑Klassen erkannt werden; in Einzelfällen lassen sich auch Use‑after‑free‑Probleme früher aufdecken. Das ist kein Ersatz für formale Safety‑Garantien, half dem Team aber praktisch beim Entwickeln und Testen.
Interoperabilität mit LLVM, statische Binaries und Toolchain
- LLVM‑Bitcode statt API: Der strategische Vorteil liegt in robusteren Upgrades und in der Möglichkeit, vorhandene, MIT‑lizenzierte Bausteine aus Zigs Codebasis wiederzuverwenden (Feldman). Das senkt langfristig die Toolchain‑Reibung.
- Statische musl‑Binaries: Für Linux‑Distributionen in Containern (inkl. Alpine) ist die einfache Bereitstellung statischer Binaries ein operativer Gewinn. Laut Feldman ist das in Zig erprobter und mit weniger Integrationsaufwand verbunden als im bisherigen Rust‑Setup.
Praktische Auswirkungen im Rewrite‑Prozess
Ein Scratch‑Rewrite ist mehr als ein Sprachwechsel – er ist ein Architektur‑Reset mit Chancen und Risiken.
- Entwicklungs‑ und Debugging‑Erfahrung: Kürzere Recompile‑Schleifen sind ein Kernziel, weil sie Produktivität und Entwicklerzufriedenheit direkt beeinflussen. Feldman nennt Wartezeiten im zweistelligen Sekundenbereich als Hemmnis – ein klarer Pull‑Faktor Richtung Zig. Gleichzeitig wird die Erwartung an künftige inkrementelle Builds als „noch nicht stabil“ markiert.
- Unsafe, FFI und Arenas: Datenorientierte Compilerteile (SoA, Indizes, Caching) führten im Rust‑Code regelmäßig zu unsafe‑Abschnitten. In Zig werden diese Muster direkter ausgedrückt, was das Team als wartungsfreundlicher einschätzt – bei gleichzeitiger Disziplin in Tests und Debug‑Praktiken.
- Testing, Fuzzing und CI: Die Quellen deuten an, dass Debug‑Instrumentierung und einfache, portable Binaries die kontinuierliche Integration erleichtern können. Konkrete Metriken liefert der Fall nicht – wichtig ist hier, Migrationshypothesen früh durch Prototypen und Messpunkte zu validieren.
Welche Lehren sich für andere Teams ableiten lassen
Die Entscheidung Rust vs. Zig ist projektabhängig. Für Teams in Deutschland, die Compiler, Runtimes oder Tools für performancekritische Pfade bauen, ergeben sich aus dem Roc‑Fall robuste Heuristiken.
Entscheidungskriterien: Wann ein Sprachwechsel sinnvoll sein kann
- Wenn ohnehin mehrere große Subsysteme neu gedacht werden müssen, kann ein gebündelter Rewrite die Architektur klarer machen als viele Teil‑Rewrites.
- Wenn Toolchain‑Ziele wie „statisch gelinkte Linux‑Binaries mit musl“ oder „LLVM‑Upgrades mit wenig Reibung“ Top‑Priorität haben, ist Zigs Ansatz (Bitcode, integrierter Build‑Pfad) eine konkrete Option.
- Wenn die Datenhaltung stark allocator‑zentriert und stufenweise isoliert ist, sind Zigs Muster (Explizitheit, SoA‑Ergonomie, Bit‑Packing) oft naheliegend. Benötigen Sie dagegen starke, host‑seitige Memory‑Safety‑Garantien an vielen Stellen, bleibt Rust ein sehr solides Fundament.
Risiken und Kosten: Scratch‑Rewrite vs. inkrementelle Migration
Ein Scratch‑Rewrite erzeugt zwangsläufig Regressionen, gerade in Edge‑Cases. Roc adressiert das, indem der Status „nicht stabil“ offen kommuniziert wird und keine strikten Release‑Kompatibilitäten versprochen sind. Für produktive Systeme in Deutschland (Finanz, Industrie, Verwaltung) ist das selten möglich; dort sind inkrementelle Wege oft die realistischere Wahl. Ausnahme: Wenn ein Projektteam die De‑Facto‑„Greenfield“‑Situation besitzt (etwa interne Tools, Forschung, neue Produkte) – dann kann ein Reset reale Vorteile bringen.
Empfehlungen für Planung, Prototyping und Messgrößen
Zwei Leitlinien helfen, Sprachwahl und Migrationspfad pragmatisch statt ideologisch zu treffen:
- Starten Sie mit einem belastbaren Technik‑Prototypen: Ziel ist eine Mini‑Pipeline, die die härtesten Annahmen berührt (z. B. Parser + Name‑Resolution + ein repräsentativer Codegen‑Pfad). Messen Sie dabei drei Dinge: Build‑/Recompile‑Zeit, Einfachheit der LLVM‑ oder Backend‑Integration, sowie die Test‑/Debug‑Erfahrung im Alltag. So erkennen Sie früh, ob die angenommenen Vorteile in Ihrem Code tatsächlich eintreten.
- Definieren Sie Team‑relevante Akzeptanzkriterien: Etwa „kalte“ und „heiße“ Buildzeiten, Rebuild nach Parser‑Änderungen, Aufwand für musl‑statische Artefakte, sowie die operativen Wege für Upgrades (LLVM, Toolchain). Halten Sie zusätzlich fest, welche Debug‑Checks Sie benötigen. Formulieren Sie Erkenntnisse klar als „in unserem Projekt beobachtet“ – wie es das Roc‑Team vorbildlich getan hat.
Fazit: Sachliche Einordnung für Entscheider und Entwickler
- Kernaussagen aus dem Roc‑Fall: Der Wechsel von Rust zu Zig ist im Roc‑Projekt keine Abkehr von Safety‑Werten, sondern eine Fokussierung auf Toolchain‑Vereinfachung, Iterationsgeschwindigkeit und Low‑Level‑Ergonomie, die zum eigenen Compilerdesign passt. Laut Feldman war die Compile‑Iteration in Rust hinderlich; Zig verspricht hier spürbare Verbesserungen, auch wenn wichtige Teile des erhofften Pfads zum Zeitpunkt der Entscheidung noch nicht stabil waren. Die LLVM‑Bitcode‑Strategie und musl‑freundliche Toolchain sind zentrale, handfeste Gründe.
- Übertragbare Erkenntnisse: Sprachwahl ist Mittel zum Zweck. Wer viele Subsysteme ohnehin neu zuschneidet, kann einen gebündelten Rewrite nutzen, um Architekturkonzepte konsequent umzusetzen. Wer stabile, langfristige Wartung mit strengen Kompatibilitäten braucht, sollte vorsichtig abwägen und frühe Prototypen strikt messen – nicht erst am Ende der Migration.
- Konkrete Fragen vor einem Rewrite: Welche Iterationszeit brauchen wir wirklich – kalt und warm? Welche Toolchain‑Pflege (LLVM, musl, statische Artefakte) dominiert unsere Kosten? Welche Speicher‑ und Datenlayout‑Muster prägen unsere Pipeline – und welche Sprache drückt sie für uns am natürlichsten aus? Können wir offene Instabilitäten (z. B. nicht stabile Backends) überbrücken, oder sind sie ein Go/No‑Go?
Der Roc‑Rewrite liefert keine Universalantwort „Rust vs. Zig“. Er zeigt aber, wie man aus echten Projektzielen, gemessenen Engpässen und klarer Roadmap zu einer tragfähigen Entscheidung kommt – und diese gegenüber Community und Nutzern transparent macht. Genau das erhöht am Ende die Erfolgschancen eines großen Rewrites – unabhängig von der gewählten Sprache.