Files
RustAst/docs/Zustand 2.md
Michael Schimmel 494bf554d2 Old Docs added
2026-02-20 10:09:22 +01:00

5.0 KiB


Projekt-Protokoll: Weiterentwicklung des Sprachdesigns

  • Datum: 08. Oktober 2025

  • Zeit: 13:22 CEST

Motivation

Die bestehende Skriptsprache bietet grundlegende funktionale und imperative Konstrukte, aber die Verwaltung von veränderlichem Zustand (def in Verbindung mit assign) ist unsicher, insbesondere im Hinblick auf Nebenläufigkeit. Das primäre Motiv für eine Weiterentwicklung ist die Schaffung einer Sprache, die aus sich selbst heraus sicher ("safe by design") ist, ohne dabei die Komplexität von Low-Level-Konzepten wie manueller Speicherverwaltung oder einem vollständigen Borrow-Checker (wie in Rust) einzuführen. Die Sprache soll auch für Programmier-Anfänger intuitiv und leicht verständlich bleiben.

Ziel

Das Ziel ist es, ein Sprachdesign zu entwickeln, das eine klare und sichere Handhabung von Zustand erzwingt. Die Kernziele des neuen Designs sind:

  1. Sicherheit durch Design: Race Conditions durch geteilten, veränderlichen Zustand sollen zur Compile-Zeit erkannt und verhindert werden.

  2. Klare Trennung von Zustandsarten: Es soll eine unmissverständliche Unterscheidung zwischen temporärem, lokalem Zustand und persistentem, geteiltem Zustand geben.

  3. Intuitive Semantik: Die Regeln der Sprache sollen den Entwickler aktiv zu sicheren und korrekten Mustern anleiten ("Pit of Success"). "Magisches" oder unvorhersehbares Verhalten des Compilers soll vermieden werden.

  4. Pragmatismus: Ein bekannter, imperativer Programmierstil soll für lokale Logik weiterhin möglich sein, um die Lernkurve flach zu halten.

Ergebnis: Das finale Sprachdesign

Wir haben uns auf ein pragmatisches Hybrid-Modell geeinigt, das funktionale Sicherheit mit imperativem Komfort kombiniert. Es basiert auf drei Säulen:

1. Sicherer globaler Zustand: def erzeugt Atome

Der def-Befehl wird modifiziert. Er dient ausschließlich zur Definition von Zustand, der potenziell über Funktionsgrenzen hinweg geteilt wird. Um dies von Natur aus sicher zu machen, erzeugt def nicht mehr einen einfachen, veränderlichen "Slot", sondern immer einen atomaren Container, der den Wert umschließt. Jede Zustandsänderung muss über explizite, threadsichere atomare Operationen (wie swap! oder reset!) erfolgen. Dies eliminiert alle Race Conditions bei globalem Zustand.

2. Veränderlicher lokaler Zustand: let mit assign

Ein neues let-Konstrukt wird eingeführt, das sich an Clojure orientiert, um einen neuen lexikalischen Gültigkeitsbereich zu schaffen. Im Gegensatz zu Clojure sind die in let definierten Bindungen jedoch standardmäßig veränderlich und können über assign modifiziert werden. Dies erlaubt Entwicklern, für rein lokale Algorithmen (z.B. Schleifen mit Zählern) einen vertrauten, imperativen Stil zu verwenden, wo Threadsicherheit keine Rolle spielt.

3. Die Sicherheitsbrücke: Statische Analyse im Binder

Dies ist die zentrale Innovation, die beide Welten sicher miteinander verbindet. Der Compiler (speziell der Binder) führt eine Escape Analysis für Closures durch, um die missbräuchliche Freigabe von unsicherem, lokalem Zustand zu verhindern. Dabei gilt eine einzige, einfache Regel:

Eine Closure, die eine veränderliche let-Variable fängt, darf nicht aus dem Gültigkeitsbereich der Funktion zurückgegeben (oder global gespeichert) werden, in der diese Variable definiert wurde.

  • Wenn eine solche "zustandsbehaftete" Closure nur lokal verwendet wird (z.B. in einem Map), ist der Code gültig.

  • Wenn versucht wird, eine solche Closure zurückzugeben oder einem globalen def zuzuweisen, erzeugt der Binder einen Compile-Fehler.

Dieser Fehler ist ein Feature, kein Mangel. Er zwingt den Entwickler, eine bewusste Entscheidung zu treffen: Entweder er strukturiert seinen Code um, oder er verwendet für den Zustand, der geteilt werden muss, explizit ein sicheres Primitiv (indem er die lokale Variable selbst zu einem (atom ...) macht).

Dieses Design vermeidet die Komplexität eines Borrow Checkers und die Unvorhersehbarkeit von "Compiler-Magie", indem es eine klare, leicht verständliche Regel zur Compile-Zeit durchsetzt.


Nächste Schritte (Todo)

  1. Binder anpassen: Implementierung der Escape Analysis für Closures. Der Binder muss let-Variablen, ihre Veränderung durch assign und das Fangen durch Closures nachverfolgen.

  2. Parser erweitern: Hinzufügen der Syntax für das neue let-Statement.

  3. def-Implementierung ändern: Die Laufzeitlogik für def muss so angepasst werden, dass sie atomare Container anstelle von rohen Werten verwaltet.

  4. RTL erweitern: Die Laufzeit-Bibliothek muss um Funktionen zur Interaktion mit Atomen erweitert werden (z.B. atom, deref, swap!, reset!).

  5. Compiler-Fehlermeldung implementieren: Eine klare und hilfreiche Fehlermeldung für den Fall entwerfen, dass die "Sicherheitsbrücke"-Regel verletzt wird.