Warum Hilde

Der Name sagt, worauf Hilde zielt: High-Integrity, Linear, Deterministic, Explicit. Hilde ist keine Kritik an Rust oder C, sondern ein anderer Ansatz mit anderen Schwerpunkten: eine kleine Sprache, eine strenge Regel für Ressourcen und Fehlermeldungen, die genau sagen, was falsch ist.

Was Hilde für Menschen leistet, leistet sie auch für KI

Hilde baut auf Austral auf (Spezifikation, ein Spiegel der Fassung auf der Austral-Website). Austral wurde so entworfen, dass man Code leicht lesen kann: wenige Konstrukte, keine Operatorrangfolge, die man auswendig kennen muss, und Fehlermeldungen, die ihre Ursache nennen. Das hilft jedem, der fremden Code liest, und einem KI-Assistenten genauso. Hilde will das Programmieren mit KI-Assistenten sicherer machen. Die typischen Fehler eines Assistenten findet ein strenger Compiler, und jeder Fehler hat einen festen Code wie H4008 mit einem Eintrag, der falschen und richtigen Code zeigt. So sieht der Assistent, was er falsch gemacht hat, und kann es beheben.

Die folgenden Abschnitte zeigen, was Hilde über Austral hinaus ergänzt hat; wo ein Teil schon aus Austral stammt, steht es dabei.

Verträge in der Sprache, nicht in einer Bibliothek

C++26 hat Verträge aufgenommen (P2900: pre, post und contract_assert). Dort legt die Implementierung fest, ob ein Vertrag ignoriert, beobachtet oder durchgesetzt wird. In Hilde gehören Verträge zur Sprache und werden immer geprüft. Eine Funktion sagt, was beim Aufruf gelten muss (requires) und was bei der Rückkehr gilt (ensures), und Records können Invarianten haben. Der Vertrag einer öffentlichen Funktion steht genau einmal, in ihrer Schnittstelle. Dort liest ihn jeder Aufrufer, ob Mensch oder KI-Assistent. Hat eine öffentliche Funktion keinen Vertrag, begründet ihr Docstring das. Verträge werden zur Laufzeit geprüft und lassen sich nicht abschalten. hilde test erzeugt aus ihnen Zufallstests, und einfache Fälle beweist der Compiler schon beim Übersetzen. Mehr dazu in den Grundlagen und bei den Entwurfsentscheidungen.

Ein Beispiel: Raft

Was eine Sprache verspricht, zeigt sich am besten an schwierigem Code. Standard.Raft ist der Konsensalgorithmus Raft als reine Zustandsmaschine. Netz, Festplatte und Uhr gehören dem Aufrufer, nicht dem Modul. Die Invarianten der Raft-Spezifikation stehen als Verträge im Code, und die Tests prüfen sie nach jedem Ereignis:

Weil die Zustandsmaschine nichts außerhalb besitzt, laufen auch die Tests mit Netzpartitionen jedes Mal gleich ab. Darauf bauen Standard.RaftTcp auf, das die Nachrichten über TCP verschickt, und Standard.SqliteReplica, das eine SQLite-Datenbank über Raft repliziert. Mehr auf der Seite Raft und bei den Datenbanken.

Typische C-Fehler vermeiden, ohne C aufzugeben

Hilde übersetzt nach C17. Das C wird mit cc, clang oder zig cc gebaut, und die Prüfläufe des Projekts verlangen unter allen drei Compilern null Warnungen. Sicherer Hilde-Code fängt die typischen C-Fehler so ab; ausgenommen sind nur die unsicheren Bindings.*-Module.

Beim Übersetzen:

Zur Laufzeit, das Programm hält mit einer Meldung an:

Lineare Typen und die Prüfung auf Überlauf hat schon Austral; neu in Hilde sind die Pflicht, Option und Either auszuwerten, die Verträge und null Warnungen unter drei Compilern.

Kein Garbage Collector

Hilde hat keinen Garbage Collector. Ein linearer Wert wird genau einmal verbraucht, und der Compiler prüft, dass jede Ressource an einer festen Stelle freigegeben wird (lineare Typen). Es gibt daher keine Pausen zum Aufräumen, und der Speicher wird dort frei, wo der Code es sagt. Für die vielen kleinen Werte einer Arbeitseinheit, etwa einer FastCGI-Anfrage, kann ein Programm Standard.Arena gezielt einsetzen: Sie gibt alles auf einmal frei, und keine Referenz daraus lebt länger als ihre Ausleihe. Unter OpenBSD wurde eine Anfrage mit 2000 kleinen Werten damit 3,3-mal schneller. Bei wenigen Werten und bei sicherheitskritischem Code bleibt das gehärtete malloc von OpenBSD die bessere Wahl. Ohne Garbage Collector war schon Austral; Standard.Arena kommt von Hilde.

Nebenläufigkeit nach dem Vorbild von Go

Nebenläufigkeit soll so leicht sein wie in Go, aber abgesichert. Deshalb laufen Tasks auf Fibers statt über Callbacks. Jeder Task gehört zu einem Scope und endet mit ihm. Die beiden Enden eines Kanals sind lineare Werte. Ein Task kann keine Referenz übernehmen, die länger lebt als ihre Ausleihe (H3002). Mehr unter Tasks und Kanäle.

Reguläre Ausdrücke und Vorlagen

Standard.Regex arbeitet in linearer Zeit und versteht die Syntax von RE2. Rückverweise und Lookaround lehnt es ab und verweist auf Standard.Pcre, das PCRE2 für die Fälle einbindet, die das wirklich brauchen. Wer von Perl kommt und PCRE schätzt, findet in Standard.Pcre die vertraute Syntax: Rückverweise, Lookahead und Lookbehind, Gruppen mit ihren Positionen und Ersetzen mit \1; mit Standard.PcreJit übersetzt der JIT von PCRE2 die Muster in Maschinencode. Vorlagen verwenden die Syntax von Jinja2, werden aber beim Übersetzen geprüft und in Hilde-Code umgewandelt. Zur Laufzeit wird nichts geparst, und eine Vorlage, die nicht zu ihrem Record passt, übersetzt gar nicht erst.

Warum HTML

Wo Hilde Webseiten erzeugt, setzt sie bewusst auf HTML. HTML kommt in den Trainingsdaten von KI-Assistenten reichlich vor, Hilde dagegen noch nicht. Vorlagen nutzen dafür die bekannte Syntax von Jinja2 (siehe oben).

„unsafe“ nur in den Bindings

Nur ein Modul mit pragma Unsafe_Module darf C einbinden, C einbetten oder rohen Speicher anfassen, und der Compiler achtet darauf. In der Standardbibliothek sind das die dünnen Bindings unter Bindings.*. Ein Programm kann sie nicht importieren (H2045), sondern verwendet das sichere Standard.*-Modul darüber. Auch der eingebaute Kern des Compilers (Hilde.Pervasive, Hilde.Memory, Hilde.Array) ist unsafe. pragma Unsafe_Module gibt es schon in Austral; neu sind die Trennung in Bindings und dass ein Programm sie nicht importieren kann. Mehr auf der Seite Sicherheit.

Nur die Laufzeit, die ein Programm braucht

Die Laufzeit von Hilde in C ist in Teile zerlegt: Kern, Tasks, Sandbox, Dateien, Sockets und weitere. Ein Programm bekommt nur die Teile, deren Funktionen es tatsächlich aufruft; Hello World trägt nur den Kern. Dadurch schrumpfte Hello World von 134 088 auf 67 808 Byte, ein Programm mit Signaturen und JSON um 17 Prozent. Weniger C im Binary heißt auch weniger Code, für den kein Vertrag gilt.

C zum Weiterarbeiten

Mit hilde compile --target-type=c schreibt Hilde ein Programm als eine einzige C17-Datei: die Teile der Laufzeit, die es braucht, der übersetzte Code und am Ende ein Kommentar mit den Bibliotheken zum Linken. Die Namen bleiben lesbar, etwa Hilde__Pervasive__abort__d9, auf Wunsch mit #line zum Hilde-Quelltext, und die Verträge stehen als gewöhnliche Prüfungen im C. Wer C kennt, kann die Datei mit cc, clang oder zig cc bauen und dort weiterarbeiten; hilde export --with-c legt sie auf Wunsch dem Release bei. Was danach im C geändert wird, prüft Hilde nicht mehr: weder die linearen Typen noch die Verträge beim Übersetzen. C als Ausgabe kann schon Austral; neu sind die lesbaren Namen, #line, die Verträge im C und --with-c.

Kommandozeilen wie mit clap

Standard.Arguments folgt der Builder-API von clap 4, dem Kommandozeilen-Parser von Rust (Command, Arg, ArgAction). Hilde folgt clap und nicht Cobra aus Go, weil die Kommandozeile bei clap ein reiner Wert mit einem Ergebnis an einer Stelle ist. Das passt zu linearen Typen und ist auch für KI-Assistenten schwerer falsch zu schreiben. Standard.Arguments geht noch weiter: Jede Option liefert einen typisierten Schlüssel. Ein Tippfehler im Optionsnamen übersetzt nicht (H6039), ein Schlüssel der falschen Art ist ein Typfehler (H3060). Für die Derive-Form von clap gibt es kein Gegenstück. Die Seite Argumente nach clap stellt clap und Hilde Aufruf für Aufruf gegenüber, mit drei Programmen, die in beiden Sprachen geschrieben und gegen clap 4.6.7 verglichen sind. Die Paketbefehle von hilde übernimmt ein Zusatzwerkzeug, das selbst in Hilde geschrieben ist und dessen Kommandozeile auf Standard.Arguments beruht. Dasselbe gilt für RAMBO. Der Compiler selbst ist (bisher) in OCaml geschrieben.

Kein Ersatz für Rust oder Zig

Rust ist eine großartige Sprache, und Hilde will sie nicht ersetzen. Hilde versucht, viele ihrer Vorteile klein, einfach und überschaubar in Code zu bringen, den ein C-Compiler überall in kleine Binaries übersetzt. Auch Zig ist eine hervorragende Sprache, die Hilde nicht ersetzen will. Hilde verdankt beiden viel: zig cc übersetzt Hilde-Programme für andere Zielsysteme und für WebAssembly und dient im vollständigen Prüflauf als weiterer Compiler. Ein Hilde-Paket kann Rust-Crates über Brückenmodule einbinden, und ML-DSA kommt aus dem C-Code von libcrux, der aus Rust erzeugt wird. Es gibt viele großartige Sprachen und Werkzeuge. Hilde ist nicht per se besser; sie ist so gebaut, wie wir es für Hilde für richtig halten.

Herkunft und Lizenz

Hilde ist ein Fork von Austral, abgezweigt beim Commit 0962d2a8 vom 29. Juli 2025. Der Compiler von Austral steht unter der Apache License 2.0 with LLVM Exception, und Hilde steht unter derselben Lizenz. Die Spezifikation von Austral steht unter der GNU Free Documentation License 1.3. Einzelheiten auf der Seite Lizenz.

Hilde verdankt vielen etwas. Wir schätzen jede Sprache und jedes Werkzeug, von dem Hilde gelernt hat, und sind dankbar dafür: Austral als Fundament, dazu Ada, Eiffel, Go, Rust, C++, C mit Zig, Perl, Python und OpenBSD. Hilde verfolgt die Idee, das, was uns daran am besten gefallen hat, in einer Sprache zusammenzubringen. Und weil Hilde selbst frei lizenziert ist, kann jeder sie nutzen.