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

110 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Die bisherige Diskussion hat sich um die Frage gedreht: "Was ist theoretisch sicher?". Du hast die Perspektive entscheidend auf die Frage gelenkt: "**Was ist praktisch nützlich und führt zu einer hohen Akzeptanz bei der Zielgruppe?**"
Ein System, das einen Domänen-Experten zwingt, ein funktionierendes, intuitives Muster in ein kompliziertes, für ihn abstraktes Muster umzubauen, nur um einen Compiler zufriedenzustellen, hat seinen Zweck verfehlt. Der Nutzer wird frustriert aufgeben.
Deine Schlussfolgerung ist daher richtig: Die "safe by design"-Garantie in ihrer strengsten Form (als harter Compiler-Fehler) ist für diesen Anwendungsfall ein Hindernis. Wir müssen das Design weiterentwickeln.
---
### Von "Guaranteed Safety" zu "Guided Safety"
Die Lösung ist nicht, die Sicherheitsanalyse abzuschaffen, sondern ihre Konsequenz zu ändern. Der Compiler sollte nicht als sturer Torwächter agieren, sondern als intelligenter Assistent, der den Nutzer aufklärt und ihm eine bewusste Entscheidung ermöglicht.
**Der neue Ansatz:**
1. Der Compiler **erkennt** das potenziell unsichere Muster (eine Closure fängt eine `var`-Variable und verlässt ihren Scope) genau wie bisher.
2. Statt eines harten **Fehlers** erzeugt er eine detaillierte **Warnung**.
3. Diese Warnung erklärt das Risiko präzise und für Laien verständlich: "Diese Funktion ist nicht threadsicher. Für isolierte Berechnungen wie Backtests ist das in Ordnung. Wenn Sie sie aber zwischen Threads teilen, kann es zu Fehlern kommen."
4. Die Warnung schlägt die Lösung vor: "Wenn Sie dies beabsichtigen, kennzeichnen Sie die Funktion explizit als nicht-threadsicher, indem Sie `fn` durch `fn!` ersetzen."
5. Der Nutzer ändert `fn` zu `fn!`. Die Warnung verschwindet. Der Nutzer hat gelernt, eine bewusste Entscheidung getroffen und kann weiterarbeiten, ohne seinen Code komplett umstrukturieren zu müssen.
Dies erreicht das Beste aus beiden Welten: Sicherheit wird nicht aufgegeben, sondern der Nutzer wird über die Risiken aufgeklärt und muss die Verantwortung explizit übernehmen.
---
Ich fasse das Ergebnis in einem neuen Projektplan-Eintrag zusammen.
### Projektplan: "Guided Safety" und der `fn!`-Modifikator
* **Datum:** 09. Oktober 2025
* **Uhrzeit:** 17:47
#### Motivation
Die strikte "safe-by-design"-Garantie, die das "Escaping" von `var`-Variablen durch einen Compiler-Fehler verhindert, erweist sich für die Zielgruppe der programmiertechnisch unerfahrenen Domänen-Experten als zu restriktiv. Sie zwingt zur Umstrukturierung von Code, der im primären Anwendungsfall (isolierte Single-Thread-Berechnungen wie Backtests) sowohl korrekt als auch performant ist. Dies führt zu Frustration und mindert die Akzeptanz der Sprache.
#### Ziel
Das Sicherheitsmodell der Sprache wird von einer rigiden **"Guaranteed Safety"** zu einer benutzerfreundlichen **"Guided Safety"** weiterentwickelt. Der Compiler soll den Nutzer auf potenzielle Gefahren hinweisen, ihn aufklären und ihm ermöglichen, eine explizite, informierte Entscheidung zu treffen, anstatt ihn mit einem harten Fehler zu blockieren.
#### Ergebnis
1. **Compiler-Warnung statt Fehler:** Der Binder wird so angepasst, dass das Fangen einer `var`-Variable durch eine "escapende" Closure nicht mehr zu einem Compiler-Fehler, sondern zu einer detaillierten **Warnung** führt.
2. **Einführung von `fn!`:** Ein neuer Funktions-Deklarations-Syntax `(fn! ...)` wird eingeführt. Dieser Modifikator signalisiert dem Compiler: "Der Programmierer hat die Warnung zur Kenntnis genommen und deklariert diese Closure absichtlich als potenziell nicht-threadsicher." Das Vorhandensein von `fn!` unterdrückt die entsprechende Compiler-Warnung.
3. **Pädagogische Fehlermeldung:** Die Warnmeldung wird so formuliert, dass sie den Sachverhalt erklärt und direkt die Lösung (`fn!` verwenden) vorschlägt. Beispiel:
> **Warnung:** Die Funktion erfasst die veränderliche Variable 'sum', die außerhalb dieses Bereichs definiert wurde. Dies macht die Funktion nicht threadsicher. Für isolierte Berechnungen (z.B. in einem Backtest) ist dies unproblematisch und performant. Um zu bestätigen, dass dies beabsichtigt ist, ändern Sie `(fn ...)` zu `(fn! ...)`."
4. **Beibehaltung der sicheren Muster:** Die bestehenden, sicheren Muster (`atom` für geteilten Zustand, `var` mit zustandslosen Funktionen) bleiben die empfohlenen Standardlösungen. `fn!` dient als explizite, bewusste Abweichung für den gut verstandenen Performance-Fall.
-------------------
> Jetzt weiß der Compiler, ob eine Closure unsafe ist. Kann er sonst noch was mit dieser Information anfangen?
Ja, absolut. Das ist eine hervorragende Frage, die den Kern von modernem Compiler-Design trifft. Die Information, ob eine Closure potenziell unsicher ist, ist weit mehr als nur ein Schalter zum Unterdrücken einer Warnung es ist ein wertvolles **Metadatum**, eine semantische Information, die das gesamte Ökosystem nutzen kann.
Stell dir das `!` bei `fn!` wie einen **"Gefahrgut"-Aufkleber** auf einem Paket vor. Es sagt nicht nur dem Absender "Vorsicht", sondern informiert die gesamte Lieferkette (Compiler, Laufzeitumgebung, andere Entwickler) darüber, wie dieses Paket zu behandeln ist.
Hier sind konkrete, extrem nützliche Dinge, die der Compiler und die Laufzeitumgebung mit dieser Information tun können:
-----
### 1\. Laufzeit-Überprüfung im Debug-Modus 💥
Das ist der größte Gewinn. Wenn der Compiler weiß, dass eine `fn!`-Closure erzeugt wird, kann er speziellen Code für den Debug-Build generieren:
1. **Beim Erstellen der Closure:** Die Laufzeitumgebung speichert die `ThreadID` des erstellenden Threads direkt in der Closure-Struktur.
2. **Bei jedem Aufruf der Closure:** Die Laufzeitumgebung prüft: `if CurrentThreadID != CapturedThreadID then`.
3. **Wenn die IDs nicht übereinstimmen**, wird sofort eine **harte Exception** ausgelöst mit einer extrem klaren Fehlermeldung:
> "Laufzeitfehler: Die nicht-threadsichere Funktion, die in Thread A (ID: 1234) erstellt wurde, wurde fälschlicherweise von Thread B (ID: 5678) aufgerufen. Dies hätte zu einer Race Condition geführt."
**Der Vorteil ist gigantisch:** Ein unvorhersehbarer, schwer zu findender Heisenbug (eine Race Condition, die nur manchmal auftritt) wird in einen **100% reproduzierbaren, sofortigen Absturz** mit perfekter Fehlerbeschreibung umgewandelt. Allein dieses Feature macht `fn!` von einer "gefährlichen" zu einer extrem nützlichen, fehlertoleranten Abstraktion.
-----
### 2\. Erweiterte Statische Analyse (Linting) 🧐
Der Compiler (oder ein separates Linter-Tool) kann diese Information für intelligentere Code-Prüfungen nutzen. Er kann die "Gefahrgut-Pakete" verfolgen:
Angenommen, es gibt eine Funktion `(parallel-map ...)` in der Standardbibliothek, die dafür bekannt ist, ihre Arbeits-Funktion auf mehreren Threads auszuführen. Die Signatur dieser Funktion kann intern vermerken, dass sie nur threadsichere Closures akzeptiert.
Wenn ein Entwickler nun versucht, Folgendes zu schreiben:
```lisp
(let my-unsafe-sma (create-sma-unsafe 20)) ; Gibt eine fn!-Closure zurück
(parallel-map my-unsafe-sma my-big-data-list)
```
Kann der Compiler an dieser Stelle eine noch spezifischere und ernstere **Warnung oder sogar einen Fehler** ausgeben:
> "Typenkonflikt: `parallel-map` erwartet eine threadsichere Funktion, aber `my-unsafe-sma` wurde mit `fn!` als nicht-threadsicher deklariert. Dies führt garantiert zu Datenkorruption."
-----
### 3\. Automatische API-Dokumentation 📖
Ein Dokumentations-Generator kann die `fn!`-Metadaten auslesen und automatisch Warnhinweise in die generierte HTML-Doku einfügen. Wenn jemand die Dokumentation für deine `CreateSMA`-Funktion liest, könnte dort stehen:
**`CreateSMA(len: Integer): Function`**
> Erzeugt eine Funktion zur Berechnung eines gleitenden Durchschnitts.
>
> ⚠️ **Thread-Sicherheit:** Diese Funktion gibt eine optimierte, nicht-threadsichere Funktion (`fn!`) zurück. Das Ergebnis darf unter keinen Umständen zwischen verschiedenen Threads geteilt werden.
Dadurch wird der API-Vertrag für jeden sofort ersichtlich, ohne dass man den Quellcode lesen muss.
-----
### Fazit
Die explizite Kennzeichnung mit `fn!` ist also kein Rückschritt in der Sicherheit. Im Gegenteil, es ist eine **semantische Anreicherung**. Sie verwandelt das Konzept von einer reinen Warnungs-Unterdrückung in einen expliziten **Vertrag**, den die gesamte Werkzeugkette Compiler, Debugger, Linter, Doku-Generator versteht und nutzen kann, um den Entwickler noch besser und intelligenter zu leiten.