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

134 lines
5.9 KiB
Markdown

-----
### Projektplan: Atome und das "Builder/Snapshot"-Pattern
* **Datum:** 09. Oktober 2025
* **Uhrzeit:** 16:07
#### Motivation
Die bisherige Diskussion hat zwei grundlegende Anforderungen an die Zustandsverwaltung herausgearbeitet:
1. **Allgemeine Sicherheit:** Für generische Datenstrukturen (Maps, Vektoren) bieten persistente Datenstrukturen durch ihre Immutabilität und lock-freie Lesbarkeit die höchste Sicherheit und Flexibilität bei konkurrierendem Zugriff.
2. **Spezialisierte Performance:** Für bestimmte Anwendungsfälle (z.B. große, append-only Time-Series) ist die Performance einer In-Place-Mutation überlegen, aber das Teilen des Zustands zwischen Threads erfordert eine sichere Synchronisation.
Die Motivation ist daher, ein **standardisiertes, generisches Muster** zu definieren, das die rohe Performance einer mutierbaren "Arbeitskopie" mit der Sicherheit von unveränderlichen, lesbaren "Snapshots" für die konkurrierende Analyse kombiniert.
#### Ziel
1. Etablierung des **"Builder/Snapshot"-Patterns** als idiomatisches Kernkonzept der Sprache für den Umgang mit hoch-performantem, geteiltem, mutablem Zustand.
2. Definition von **generischen Basis-Interfaces** (`IBuilder`, `IImmutable`), die dieses Pattern im Typensystem verankern.
3. Nahtlose Integration dieses Patterns mit den bestehenden `atom`- (für geteilten Zustand) und `var`- (für lokalen Zustand) Konstrukten.
#### Ergebnis
Das Ergebnis ist ein klares, zweigleisiges Modell für die Zustandsverwaltung, das auf dem generischen "Builder/Snapshot"-Pattern aufbaut.
**1. Das generische Pattern: `IBuilder` / `IImmutable`**
Wir definieren zwei konzeptionelle Basis-Interfaces, die den Vertrag des Patterns abbilden:
* `IImmutable`: Ein **Marker-Interface**, das einen sicheren, unveränderlichen "Produkt"- oder Snapshot-Typ kennzeichnet.
* `IBuilder`: Ein Interface, das einen "Builder" kennzeichnet. Es definiert die Fähigkeit, ein `IImmutable`-Produkt zu erzeugen.
**2. Die Spezialisierung (Beispiel: `Series`-Interfaces)**
Konkrete Datenstrukturen wie die `Series` spezialisieren diese generischen Rollen.
```delphi
// --- Generische Basis-Interfaces ---
// Kennzeichnet ein sicheres, unveränderliches Lese-Objekt (Snapshot).
IImmutable = interface(IInterface)
end;
// Kennzeichnet ein mutierbares Builder-Objekt, das Snapshots von sich erzeugen kann.
IBuilder = interface(IInterface)
function CreateSnapshot: IImmutable;
end;
// --- Spezialisierte Interfaces für die 'Series' ---
// ISeries ist die spezialisierte, lesbare Form von IImmutable.
ISeries = interface(IImmutable)
function GetCount: Int64;
function GetItems(Idx: Integer): TScalar;
property Count: Int64 read GetCount;
property Items[Idx: Integer]: TScalar read GetItems; default;
end;
// IWriteableSeries ist der spezialisierte Builder.
// Wichtig: Er implementiert den IBuilder-Vertrag, indem er eine CreateSnapshot-Methode
// anbietet, die den spezialisierten Snapshot-Typ ISeries zurückgibt.
IWriteableSeries = interface(IBuilder)
function GetCount: Int64;
property Count: Int64 read GetCount;
procedure Add(const Item: TScalar.TValue; Lookback: Int64 = -1);
function CreateSnapshot: ISeries; // Covarianter Return-Type zum Basis-Interface
end;
```
**3. Die Anwendungsbeispiele in der Sprache**
Das Pattern wird auf zwei Arten verwendet, je nach Kontext (`atom` oder `var`). Die RTL-Funktionen arbeiten mit den generischen `IBuilder`- und `IImmutable`-Konzepten.
**Beispiel 1: Geteilter Zustand (via `atom`)**
Der `atom` schützt den `IBuilder` vor konkurrierenden Schreibzugriffen.
```lisp
(*
* Szenario: Ein Ticker-Modul (Thread A) empfängt Live-Daten,
* während eine UI (Thread B) die Daten zur Analyse anfordert.
*)
; Ein globaler 'atom' wird erstellt. Er hält die einzige Instanz des Builders.
(atom live-ticker (create-series-builder))
; -- Thread A (Produzent) --
; Modifiziert den Builder sicher über eine generische, synchronisierte RTL-Funktion,
; die auf jedem IBuilder in einem Atom funktioniert.
(builder-update! live-ticker series-add new-tick-value)
; -- Thread B (Konsument) --
; Fordert einen sicheren, unveränderlichen Snapshot an.
; Die generische 'snapshot'-Funktion ruft intern 'CreateSnapshot' auf.
(let chart-data (snapshot live-ticker))
; 'chart-data' ist nun eine sichere ISeries (IImmutable), die ohne Locks gelesen werden kann.
(calculate-indicators chart-data)
```
**Beispiel 2: Lokaler Zustand (via `var`)**
Dies ist der "Maschinenraum"-Modus für maximale Single-Thread-Performance.
```lisp
(*
* Szenario: Innerhalb einer Funktion wird eine komplexe Datenreihe
* temporär aufgebaut, um ein einmaliges Ergebnis zu berechnen.
*)
(do
; Erzeuge einen lokalen, unsynchronisierten Builder.
(var local-builder (create-series-builder))
; Befülle den Builder direkt und ohne Lock-Overhead über typspezifische,
; unsynchronisierte RTL-Funktionen.
(repeat 1000000
(series-add! local-builder (get-next-value)))
; Erzeuge einen finalen Snapshot für die Weiterverarbeitung.
(let final-data (series-create-snapshot local-builder))
; Gib das Ergebnis der Analyse zurück.
(run-analysis-on final-data))
```
#### Todo
* [ ] Generische `IBuilder`- und `IImmutable`-Interfaces in Delphi definieren.
* [ ] Finale `ISeries`- und `IWriteableSeries`-Interfaces (als Spezialisierungen) implementieren.
* [ ] Eine konkrete `TSeries`-Klasse implementieren, die `IWriteableSeries` implementiert.
* [ ] Die generischen, synchronisierten RTL-Funktionen `(builder-update! ...)` und `(snapshot ...)` für `atom`s erstellen, die auf `IBuilder` operieren.
* [ ] Die spezifischen, unsynchronisierten RTL-Funktionen `(series-add! ...)` und `(series-create-snapshot ...)` für die `TSeries`-Implementierung erstellen.
* [ ] Unit-Tests für beide Anwendungsfälle schreiben.