JDL – Modulsystem und FFI¶
Status: Draft
Geltungsbereich: Sprachebene (keine VM-Implementierungsdetails)
Warum Dieses Dokument Existiert¶
Sobald aus Sprachfeatures echte Projekte werden, entstehen zwei Druckpunkte:
- Modulgrenzen müssen klar sein (Sichtbarkeit, Imports, API-Kontrolle).
- FFI muss sicher eingebettet werden, ohne das Effektsystem zu verwässern.
Dieses Dokument fixiert genau diese Übergänge.
0. Priorität¶
Ergänzt:
00-refinements.md01-grundlagen.md02-typsystem.md03-runtime.md
Bei Widerspruch gelten 00 bis 03.
1. Leitbild¶
- modulare Struktur über Dateipfade,
- klare Trennung zwischen
service(Vertrags-/Abstraktionsebene) undextern(FFI-Deklaration), - eine einzige Service-Zuordnungsform:
provide Service for Handler.
2. Modulsystem¶
2.1 Grundregeln¶
- Dateipfad bestimmt Modulname (
users/service.jdl->users::service). mod.jdlist optionales API-Root.- Sichtbarkeit folgt der Namespace-Spec: privat (default),
package,pub. - Zyklische Modulabhängigkeiten sind Compilerfehler.
2.2 Sichtbarkeit¶
// users/service.jdl
def validateEmail(email: str) -> bool { ... } // privat
package def normalizeEmail(email: str) -> str
pub def findUser(email: str) -> Result[User, UserError]
pub type User: struct { ... }
2.3 Importformen¶
import users::service
import users::service : User, findUser
import users::service : User as AppUser
Vollimport ist explizit, kein impliziter Wildcard-Trick.
2.4 mod.jdl als API-Schicht¶
// users/mod.jdl
pub import package::model : User, UserId
pub import package::service : findUser, registerUser
Damit kann öffentliche API bewusst geformt werden.
Module unter einem internal-Teilbaum folgen zusätzlich der Namespace-Spec und sind außerhalb des aktuellen Packages/Plugins nicht importierbar.
2.5 Lokale Imports¶
Erlaubt für lokale Lesbarkeit, aber kein Ersatz für explizite Service-Parameter
oder Effect[R, E, D]-Rückgabetypen.
3. Service vs. extern¶
3.1 Rollen¶
protocol: typbezogenes Verhalten,service: Vertrags-/Abstraktionsebene, die überprovide Service for Handleran konkrete Implementierungen gebunden wird,extern: rohe FFI-Bindings.
3.2 Harte Trennung¶
extern-Blöcke sind nie selbst Service-Abstraktionen,extern-Blöcke enthalten nurdef-Deklarationen,- Domänenlogik/Fehlermapping im Handler (
provide ... for ...), implementsexistiert nicht.
3.3 Verbindliche Zuordnung¶
Nicht zulässig:
provide HandlerType for ServiceNameextern X : implements Y
4. FFI-Modell¶
4.1 Grundsyntax¶
extern LibSQLite {
def query(db: DbHandle, sql: str) -> Result[RowSet, SqliteError] {
...
} :> CSymbol("sqlite3_exec")
} :> FFILink("sqlite3")
4.2 Service darüber anbieten¶
service Db {
def query(sql: str) -> Result[RowSet, DbError]
}
type SqliteHandler: struct { db: DbHandle }
provide Db for SqliteHandler {
def query(self, sql: str) -> Result[RowSet, DbError] {
LibSQLite.query(self.db, sql)
|> Result.mapErr(DbError.from)
}
}
4.3 Syntaxkonsistenz¶
def innerhalb von extern-Blöcken, nicht fn.
4.4 FFI-Typsicherheit¶
Erlaubt:
- primitive Skalare,
ptr[T]nur an expliziten FFI-Grenzen,- opaque Handles,
- ABI-kompatible Struct/Enum-Repräsentationen.
Nicht erlaubt:
- captured Closures,
- arena-gebundene Typen über falsche Grenzen,
- lokale Share-Typen über unzulässige Übergänge,
- unklare generische ABI-Signaturen.
5. Normative Invarianten¶
- Service-Zuordnung nur via
provide Service for Handler. implementsist kein Sprachbestandteil.extern-Blöcke sind keine Service-Abstraktionen und werden nicht direkt als Vertragsoberfläche verwendet.extern-Blöcke enthalten keine Domänenlogik.- FFI-Einstieg benutzt
definnerhalb vonextern-Blöcken. - Symbolbindung läuft über Refinements (
:> CSymbol(...)). - Library-Linkage läuft über
:> FFILink(...)auf demextern-Block.
6. Offene Punkte (Phase 2)¶
- Callback-Brücken,
- detaillierte ABI/Calling-Convention-Policies,
- formale
repr: C-Regeln, - Paketmanager-/Versionsauflösung außerhalb Sprachkern.