Zum Inhalt

Dispatch Modes in JDL

Status: Normativ (v0.1)
Geltungsbereich: Sprachsemantik, VM-Dispatch, Protocol-System
Abhängigkeiten: 02-typsystem.md, 11-jadevalue-und-register-layout.md


1. Ziel

JDL unterscheidet zwischen statischer Bindung, generischer Bindung und dynamischer Bindung von Protocol-Operationen.
Diese Unterscheidung ist semantisch relevant für:

  • Aufrufauflösung
  • Performance-Modell
  • Runtime-Repräsentation
  • VM-Dispatch
  • API-Design

Generics implizieren keine dynamische Bindung.
Dynamic Dispatch ist ein eigener Modus und muss semantisch explizit sein.


2. Begriffe

2.1 Static Dispatch

Ein Aufruf ist statisch gebunden, wenn der konkrete Operandentyp und die zugehörige Protocol-Bindung zur Compile-Zeit feststehen.

Beispiele:

  • konkrete Operatoranwendung auf bekannten Typen
  • direkter Methodenaufruf auf bekanntem Typ
  • bekannte provide P for T-Bindung

2.2 Generic Dispatch

Ein Aufruf ist generisch gebunden, wenn der Code über Typparameter formuliert ist, die konkrete Instanz jedoch pro Verwendung spezialisierbar oder anderweitig compile-time auflösbar ist.

Generic Dispatch ist kein Dynamic Dispatch.

2.3 Dynamic Dispatch

Ein Aufruf ist dynamisch gebunden, wenn an der Aufrufstelle nur bekannt ist, dass ein Wert ein Protocol P erfüllt, nicht jedoch, welcher konkrete Typ T zur Laufzeit vorliegt.

Dynamic Dispatch erfordert eine Runtime-Repräsentation der Protocol-Bindung.


3. Semantische Regel

JDL kennt drei getrennte Kategorien von Werten.

3.1 Konkrete Werte

Der konkrete Typ ist bekannt.

val x: i32 = 1
val y: i32 = 2
x + y

Die Auflösung erfolgt statisch.

3.2 Generische Werte

Der Code ist über Typparameter formuliert.

def addPair[T](a: T, b: T) -> T
    a + b

Die Bindung von + erfolgt pro konkreter Instanz von T durch Spezialisierung oder compile-time resolution.

3.3 Dynamische Protocol-Werte

Es ist nur bekannt, dass ein Wert Protocol P erfüllt.

Beispielhafte Notation, Syntax offen:

val x: dyn Printable  // spekulativ

oder semantisch äquivalent.

Die konkrete Implementierung von Printable wird erst zur Laufzeit bestimmt.


4. Grundsatz

4.1 Default

JDL bevorzugt statische Bindung.

4.2 Generics

Generics sind standardmäßig statisch bzw. generisch spezialisiert, nicht dynamisch.

4.3 Dynamic Dispatch

Dynamic Dispatch ist nur zulässig, wenn ein Wert explizit als Protocol-erased, existential oder anderweitig dyn-artig modelliert ist.


5. Motivation für Dynamic Dispatch

Dynamic Dispatch ist in JDL für Fälle vorgesehen, in denen der konkrete Typ nicht Teil der statischen API sein soll oder nicht vorab bekannt sein kann.

Legitime Anwendungsfälle:

  • heterogene Collections
  • Plugin- und Modulgrenzen
  • Service-Registries
  • Runtime- und Hostobjekte
  • REPL, Tooling, Reflection, Inspection
  • API-Grenzen mit bewusst verborgenem konkretem Typ

Nicht-legitime Verallgemeinerung:

  • generischer Code allein ist kein Grund für Dynamic Dispatch

6. Runtime-Modell

Dynamic Dispatch wird in JDL nicht als klassisches OO-VTable-Modell vorausgesetzt, sondern als Runtime-Auflösung einer Protocol-Bindung.

6.1 Abgrenzung zu JadeValue

Ein dynamischer Protocol-Wert (dyn P) ist kein JadeValue im Sinne des normalen Register- und Grenzmodells (siehe 11-jadevalue-und-register-layout.md).

JadeValue ist ein ungetaggter Transportcontainer, dessen Interpretation durch den Bytecode-Kontext statisch bekannt ist. dyn P ist dagegen präzise der Fall, in dem der konkrete Typ an der Aufrufstelle nicht statisch bekannt ist — der fundamentale Widerspruch zu JadeValues No-Tag-Invariante.

Daraus folgt: dyn P-Werte sind eine eigene VM-interne Kategorie, die semantisch oberhalb von JadeValue liegt.

6.2 Wertebenen im Überblick

Ebene Beschreibung Tag?
Statischer / generischer Wert VM-interner Registerwert, kontextgetypt nein
JadeValue Grenzformat für Call/Return/Intrinsic/FFI nein (Bytecode-Kontext)
dyn P-Existential Container Eigene VM-Kategorie, Runtime-Typinfo ja (erforderlich)

6.3 DynValue — die VM-interne Struktur

Ein dyn P-Wert ist ein DynValue — ein JadeValue-Wrapper mit persistenter Typidentität:

// D-Implementierung (normativ für Struktur, nicht für Syntax)
struct DynValue {
    JadeValue payload;  // der verborgene Wert — Immediate oder Handle
    TypeId    typeId;   // persistente Runtime-Typidentität
}

DynValue ist größer als ein einzelner JadeValue-Slot (> 8 Byte) und wird daher vom JME auf dem Heap alloziert. An Funktionsgrenzen reist ein dyn P-Wert als normales JadeValue.handle — ein HandleId der auf den heap-allozierten DynValue zeigt.

Das ist strukturell identisch zu Rusts Box<dyn Trait>: Heap-Allokation des verborgenen Werts plus Metadaten, Transport als Pointer/Handle. Der Unterschied: Jade delegiert Ownership und Lifetime-Management ans JME statt an Box/Arc.

Konsequenz: Jeder dyn P-Wert kostet eine JME-Allokation — auch wenn der verborgene Payload ein i32 ist. Das ist für die legitimen Anwendungsfälle von dyn (Plugin-Grenzen, Service-Registries, heterogene Collections) akzeptabel, da diese typischerweise einmalig bei Initialisierung stattfinden, nicht in engen Loops.

6.4 Binding-Auflösung

Die interne Repräsentation der Binding-Auflösungsmetadaten — ob Lookup-on-use, captured Witness, Protocol Table oder Strategy Slot pro (T, P) — ist VM-intern und nicht Teil des Sprachvertrags. Normativ ist nur: korrekte Binding-Auflösung zum Aufrufzeitpunkt muss garantiert sein.


7. Auflösungsregeln

7.1 Static Dispatch

Wenn T bekannt ist und P für T eindeutig gebunden ist, wird direkt auf die zugehörige Zielroutine oder VM-Strategie verwiesen.

7.2 Generic Dispatch

Wenn ein Aufruf über T generisch formuliert ist, wird die zugehörige Protocol-Bindung für jede konkrete Instanz von T compile-time oder instantiation-time bestimmt.

7.3 Dynamic Dispatch

Wenn ein Wert nur als dyn P oder äquivalent vorliegt, wird zur Laufzeit das Binding für (runtime_type(value), P) aufgelöst.


8. Performance-Modell

JDL garantiert nicht, dass Dynamic Dispatch dieselben Optimierungseigenschaften wie Static Dispatch besitzt.

Im Allgemeinen gilt:

  • Static Dispatch: direkt, optimierbar
  • Generic Dispatch: spezialisierbar, häufig statisch
  • Dynamic Dispatch: indirekt, runtime-abhängig

Dynamic Dispatch soll in JDL ein gezieltes Werkzeug, nicht das Standardmodell allgemeiner Protocol-Verwendung sein.


9. Beziehung zu Protocols

Protocols in JDL sind zunächst Verträge. Ob ein Protocol-Aufruf statisch, generisch oder dynamisch gebunden wird, hängt nicht vom Protocol selbst, sondern vom Wertmodus an der Aufrufstelle ab.

Daraus folgt:

  • Printable als Constraint in Generics ist nicht dyn
  • Printable auf konkretem Typ ist nicht dyn
  • nur ein explizit dynamischer Protocol-Wert erzeugt Dynamic Dispatch

10. Beziehung zu provide und derive

10.1 provide

provide P for T definiert eine Protocol-Bindung. Diese Bindung kann sowohl statisch als auch dynamisch verwendet werden, abhängig vom Aufrufkontext.

10.2 derive

derive: [P] oder :> Derive([P]) erzeugt oder beantragt eine Protocol-Bindung für T. Auch daraus folgt nicht automatisch Dynamic Dispatch.

Dynamic Dispatch hängt nicht an der Herkunft der Binding-Entstehung, sondern an der Repräsentation des verwendeten Werts.


11. Nicht-Ziele

JDL behandelt Protocols nicht automatisch als OO-Interfaces mit implizitem Runtime-Polymorphismus.

Insbesondere gilt:

  • Protocol ≠ dyn
  • Generic Constraint ≠ dyn
  • derive(P) ≠ dyn
  • provide P for T ≠ dyn

Dynamic Dispatch ist eine gesonderte semantische Kategorie.


12. Offene Syntaxfrage

Die Syntax für dynamische Protocol-Werte ist derzeit offen. Mögliche Richtungen:

  • dyn Printable
  • any Printable
  • exists Printable
  • Printable*
  • andere spezielle Existential-Notation

Unabhängig von der finalen Syntax bleibt die Semantik dieses Dokuments verbindlich:

Ein dynamischer Protocol-Wert ist ein Wert mit bekannter Protocol-Erfüllung, aber verborgenem oder erst zur Laufzeit bekanntem konkreten Typ.


13. Kurzfassung

JDL unterscheidet zwischen statischer, generischer und dynamischer Protocol-Bindung. Generics sind nicht dynamisch. Dynamic Dispatch entsteht nur bei explizit protocol-erased bzw. existential modellierten Werten. Ein dyn P-Wert ist kein JadeValue, sondern ein VM-interner Existential Container mit Runtime-Typinformation und Metadaten zur Binding-Auflösung für (runtime_type, protocol).


Änderungsprotokoll

v0.1 — Initiale Fassung als Appendix.
v0.3 — Section 6 konkretisiert: DynValue-Struktur als JadeValue-Wrapper mit persistenter TypeId normativ eingeführt. JME-Heap-Allokation als Transportstrategie festgelegt (analog zu Rusts Box<dyn Trait>). Binding-Auflösung explizit als VM-intern klassifiziert. Section 6.3/6.4 umstrukturiert.

v0.2 — Zu normativem Spec-Dokument erhoben. Section 6 grundlegend überarbeitet: Abgrenzung zu JadeValue, Wertebenen-Tabelle, normative Anforderungen an den Existential Container, Verweis auf 10-runtime-handles und 11-jadevalue-und-register-layout ergänzt. Syntaxbeispiele mit // spekulativ markiert.