6.0 KiB
Design — Formularmodell und Objektsprache
Context
Siehe proposal.md — Why. Drei Bestandsbefunde schneiden den Entwurf zu:
- Der Punkt gehört heute zum Bezeichner. Der Lexer nimmt
.in den Namen auf (a.bist ein Token), die Semantik zerlegt ihn nur, wenn die Basis ein UDT ist. Ein Objektzugriff fällt deshalb durch bis zur impliziten Variablen. !ist heute immer Typsuffix.Form1!Text1liest sich alsForm1(SINGLE) gefolgt vonText1.- Der Rückrufweg existiert bereits aus
phase-4-ereignisschleife: die VM kann ein Ziel anspringen und zurückkehren. Ereignisprozeduren brauchen davon die Variante „Prozedur mit Argumenten" statt „GOSUB-Ziel".
Goals / Non-Goals
Goals:
- Objektzugriffe, die zur Übersetzungszeit gegen die Klasse geprüft werden — kein Nachschlagen von Eigenschaftsnamen zur Laufzeit im Normalfall.
- Ein Formularmodell, das die Steuerelemente des Folge-Changes nur noch füllen, nicht umbauen müssen.
- Modales
SHOWohne zweiten Ausführungsstrang.
Non-Goals:
- Darstellung und Eingabebehandlung der Steuerelemente.
- Ein offenes Objektsystem für Anwenderklassen (Stufe 2).
Decisions
D1 — Objektnamen werden zur Übersetzungszeit aufgelöst
Formulare und Steuerelemente sind zur Übersetzungszeit bekannt: sie
stammen aus der .FRM-Beschreibung bzw. dem Formular-Designer. Der
Compiler löst Text1.Text deshalb in „Objekt 7, Eigenschaft 12" auf und
prüft Typ und Schreibbarkeit sofort.
| Alternative | Warum nicht |
|---|---|
| Eigenschaftsnamen zur Laufzeit nachschlagen | Verlagert jeden Tippfehler in eine Laufzeitmeldung — genau die stille Lücke, die der Guiding Principle verbietet; zudem eine Hashsuche pro Zugriff |
Der Zugriff über CONTROL-Parameter (SUB Setze (c AS CONTROL)) bleibt
dynamisch; dort prüft die Laufzeit und TYPEOF fragt die Klasse ab.
D2 — Der Punkt wird im Lexer nicht mehr gefaltet, sondern im Parser zerlegt
Der Lexer liefert weiterhin ein Token, das Punkte enthalten kann (die
Rückwärtskompatibilität für Variablennamen mit Punkt bleibt: klassische
Programme nutzen Kunde.Name als gewöhnlichen Variablennamen). Die
Auflösung entscheidet die Semantik in dieser Reihenfolge:
Basis ist UDT-Variable -> Feldzugriff wie bisher
Basis ist Formular/Control -> Eigenschaftszugriff
Basis ist SCREEN -> Bildschirmobjekt
sonst -> Diagnose mit Basis- und Gliedname
(heute: implizite Variable)
Damit ändert sich für bestehende Programme nichts, solange kein Objekt den Namen trägt; Objekte gewinnen gegen implizite Variablen, weil implizite Variablen mit Punkt im Namen ohnehin ein Bug waren.
D3 — ! entscheidet sich am folgenden Token
Folgt auf ! unmittelbar ein Bezeichner, ist es der Container-Operator;
sonst das Typsuffix. Wert! = 1.5 und Form1!Text1.Text = "a" sind
damit unterscheidbar, ohne dass der Lexer wissen muss, was Form1 ist.
Der Fall Wert!Text — SINGLE-Variable direkt gefolgt von einem
Bezeichner — ist in keiner gültigen Syntax des Dialekts erreichbar.
D4 — Modales SHOW ist ein Frame-Zustand, kein zweiter Strang
SHOW 1 markiert den aufrufenden Frame als „wartet auf Formular X" und
gibt an die Ereignisschleife zurück. Die Schleife stellt weiter zu; wird
X entladen oder verborgen, läuft der markierte Frame an der Anweisung
nach SHOW weiter.
Form1.SHOW 1
|
+-- Frame markieren (wartet auf Form1) --> Ereignisschleife
|
Ereignisse zustellen <--+
|
UNLOAD Form1 ------------+
|
PRINT "danach" <-- Marke faellt, Frame laeuft weiter
Eine geschachtelte Schleife innerhalb des SHOW-Aufrufs wäre die
naheliegende Variante, macht aber die Stapeltiefe von der Zahl
verschachtelter modaler Formulare abhängig und verträgt sich nicht mit
dem Einzelschritt des Debuggers in Phase 5.
D5 — Ereignisprozeduren sind gewöhnliche Prozeduren mit fester Signatur
Der Dispatch ruft Command1_Click wie jeden anderen Prozeduraufruf, nur
angestoßen von der Schleife statt von einer Anweisung. Damit gelten
Frames, ON ERROR, EXIT SUB und der Debugger unverändert. Die
Zuordnung Name → Objekt/Ereignis entsteht zur Übersetzungszeit; zur
Laufzeit ist es ein Index.
D6 — Das Inventar bekommt eine zweite Quelle
Die Themenliste der Original-Hilfe führt das Objektmodell nicht. Statt es unerfasst zu lassen — und damit die Abnahme der Phase 6 blind zu machen —, führt das Inventar Eigenschaften, Methoden und Ereignisse je Klasse mit der Forms-Referenz als Quelle. Der bestehende Abgleichstest prüft sie mit denselben Regeln.
Größenordnung: 17 Klassen, in Summe einige hundert Einträge. Das ist der Preis dafür, dass „Vollständigkeit ist das Soll" für Forms überhaupt messbar wird.
Risks / Trade-offs
- Namenskollision Objekt gegen Variable → Objekte gewinnen; ein
Programm mit einer Variablen
Text1und einem SteuerelementText1bekommt eine Diagnose statt einer stillen Umdeutung. - Der Inventarzuwachs erschlägt die Tabelle → eigene Gruppe je Klasse, damit die bestehenden Gruppen lesbar bleiben; der Abgleichstest nennt weiterhin einzelne Einträge.
- Modale Marke und Debugger → der Fortsetzungspunkt ist derselbe
Mechanismus wie
STOP/CONT; er wird zusammen mit Phase 5 geprüft. .FRMfehlt noch → bis dahin entstehen Formulare im Test aus einer im Code aufgebauten Beschreibung; das Objektmodell hängt nicht am Dateiformat.
Open Questions
- Z-Reihenfolge bei überlappenden Steuerelementen (offene Detailfrage der Forms-Referenz) — betrifft die Darstellung, nicht das Objektmodell.
- Ob
ControlPanelalle 18 Systemfarbwerte des Vorbilds abbildet oder eine Teilmenge, entscheidet sich mit der Darstellung im Folge-Change.