Module und Import-System
Jede Lyx-Quelldatei ist gleichzeitig ein Modul (in Lyx-Terminologie: eine Unit). Die Unit-Deklaration am Dateianfang legt den Namensraum fest. import lädt eine andere Unit und macht ihre öffentlichen Symbole sichtbar. pub steuert, welche Symbole exportiert werden.
Das System ist bewusst einfach: keine Pakete, keine Versionsverwaltung im Sprachkern, keine zyklischen Importe. Eine Unit = eine Datei = ein Namensraum.
→ Syntax-Referenz · Erste Schritte · Standard Library
1. Unit-Deklaration
Jede .lyx-Datei beginnt mit einer unit-Deklaration:
unit my_module;
Pflichtregeln:
- Der Unit-Name muss exakt mit dem Dateinamen übereinstimmen (ohne
.lyx-Endung) - Unterverzeichnisse werden durch Punkte getrennt: Datei
net/http_client.lyx→unit net.http_client; - Erlaubte Zeichen: Kleinbuchstaben, Ziffern, Unterstriche. Keine Großbuchstaben, keine Bindestriche.
- Die
unit-Zeile muss die erste Zeile der Datei sein (vor jedem Import, vor jedem Kommentar).
// Datei: sensors/temp_reader.lyx
unit sensors.temp_reader;
import std.io;
import std.math;
2. Import-Syntax
Imports folgen direkt auf die Unit-Deklaration, vor allen anderen Deklarationen:
unit my_app;
// Standardbibliothek
import std.io;
import std.string;
import std.net.socket;
// Eigene Units
import sensors.temp_reader;
import utils.math_helpers;
- Die Import-Reihenfolge spielt keine Rolle für den Compiler.
- Mehrere Imports der gleichen Unit sind erlaubt, aber redundant.
- Zirkuläre Importe (A importiert B, B importiert A) sind nicht erlaubt und erzeugen einen Compiler-Fehler.
- Eine Unit kann sich nicht selbst importieren.
Qualifizierte Namen
Nach dem Import sind alle pub-Symbole der Ziel-Unit direkt (unqualifiziert) sichtbar:
import std.string;
fn Greet(name: pchar): void {
var upper: pchar := alloc(256);
StrToUpper(upper, name); // kein "string." Prefix nötig
Print(upper);
}
Wenn zwei importierte Units dasselbe Symbol exportieren, entsteht eine Namenskollision. Der Compiler meldet das als Fehler. Lösung: Einen der Importe weglassen oder die Symbole umbenennen (derzeit kein Alias-Import).
3. Sichtbarkeit mit pub
Standardmäßig ist alles privat — nur innerhalb der eigenen Unit sichtbar. pub macht ein Symbol exportierbar:
Funktionen
unit math_utils;
// Öffentlich — von anderen Units importierbar
pub fn Square(x: int64): int64 {
return x * x;
}
// Privat — nur innerhalb math_utils sichtbar
fn SquareInternal(x: int64): int64 {
return x * x;
}
Konstanten
unit constants;
pub con PI: f64 := 3.14159265358979;
pub con MAX_CONN: int64 := 1024;
con INTERNAL_BUF: int64 := 4096; // privat
Variablen
unit config;
pub var LogLevel: int64 := 2; // Von außen lesbar und schreibbar
var _internalState: int64 := 0; // Privat
Öffentliche Variablen (pub var) sind selten sinnvoll — sie erzeugen globalen Zustand der von jeder importierenden Unit verändert werden kann. Bevorzugepub fn Get…()/pub fn Set…()Accessoren.
Typen, Enums, Structs, Klassen
unit geometry;
// Öffentlicher Typ — andere Units können Point verwenden
pub type Point = struct {
x: f64;
y: f64;
};
// Öffentliches Enum
pub enum Axis { X, Y, Z }
// Privater Hilfstyp — nur intern
type InternalMatrix = struct { data: int64; };
4. Namensraum und Kollisionen
Lyx hat keine explizite Namespace-Syntax — jede Unit ist ihr Namensraum. Nach dem Import sind alle pub-Symbole direkt im lokalen Scope sichtbar.
import std.db.sqlite; // exportiert: SQLiteOpen, SQLiteClose, SQLITE_ROW, ...
import std.db.postgres; // exportiert: PGConnect, PGClose, PGQuery, ...
// Kein Konflikt — unterschiedliche Präfixe per Konvention (SQLite* vs. PG*)
var db: int64 := SQLiteOpen("/data/app.db");
var conn: int64 := PGConnect("localhost", 5432, "mydb", "user", "pass");
Die Standardbibliothek nutzt konsequent Unit-spezifische Präfixe als Konvention, um Kollisionen ohne Namespace-Qualifier zu vermeiden:
| Unit | Prefix-Konvention | Beispiel |
|---|---|---|
std.db.sqlite | SQLite* | SQLiteOpen, SQLITE_ROW |
std.db.postgres | PG* | PGConnect, PGQuery |
std.pdf.builder | Pdf* | PdfCreate, PdfSave |
std.net.socket | TCP* / UDP* / Socket* | SocketTCPListen |
std.string | Str* / Char* | StrFind, CharToUpper |
std.crypto.aes | AES* | AESEncryptBlock |
Eigene Units sollten dasselbe Muster verwenden — kurzer, eindeutiger Präfix vor allen öffentlichen Symbolen.
5. Standard Library importieren
Die Standardbibliothek liegt im std.-Namespace. Alle wichtigen Units:
// Basisfunktionalität
import std.io; // Print, PrintLn, ReadLine, ...
import std.string; // StrFind, StrReplace, StringBuilder, ...
import std.alloc; // malloc, free_mem, ...
import std.math; // Sin, Cos, Sqrt, Floor, ...
import std.result; // Result<T, E>
// Netzwerk
import std.net.socket; // TCP, UDP, Unix Sockets
import std.net.http; // HTTP/1.1 Client
import std.net.dns; // DNS-Auflösung
// Datenbanken
import std.db.sqlite; // SQLite3
import std.db.postgres; // PostgreSQL
import std.db.redis; // Redis
// PDF
import std.pdf; // PDF erstellen (High-Level-Einstiegspunkt)
// Crypto
import std.crypto.aes; // AES-Verschlüsselung
import std.hash; // Hashing
// System
import std.fs; // Dateisystem
import std.process; // Prozessverwaltung
import std.thread; // Threads
import std.time; // Zeitfunktionen
import std.env; // Kommandozeilenargumente
Alle verfügbaren Units: → Standard Library — vollständige Übersicht
6. Eigene Multi-Unit-Projekte strukturieren
Eine typische Projektstruktur mit mehreren Units:
my_project/
├── main.lyx → unit main;
├── config.lyx → unit config;
├── db/
│ ├── connection.lyx → unit db.connection;
│ └── queries.lyx → unit db.queries;
└── api/
├── handler.lyx → unit api.handler;
└── response.lyx → unit api.response;
// db/connection.lyx
unit db.connection;
import std.db.postgres;
pub con DB_HOST: pchar := "localhost";
pub con DB_PORT: int64 := 5432;
pub fn Connect(dbName: pchar): int64 {
var conn: int64 := PGConnect(DB_HOST, DB_PORT, dbName, "app", "secret");
if (conn == 0 || PGIsConnected(conn) == 0) { return 0; }
return conn;
}
// api/handler.lyx
unit api.handler;
import std.io;
import std.net.http;
import db.connection; // eigene Unit — relativer Pfad
pub fn HandleGetUsers(conn: int64): void {
// conn kommt aus db.connection.Connect(...)
var res: int64 := PGQuery(conn, "SELECT id, name FROM users");
// ...
}
// main.lyx
unit main;
import std.io;
import db.connection;
import api.handler;
pub fn main(): int64 {
var conn: int64 := Connect("myapp");
if (conn == 0) {
PrintLn("Datenbankverbindung fehlgeschlagen");
return 1;
}
HandleGetUsers(conn);
PGClose(conn);
return 0;
}
7. Suchpfad und Compilation
Der Compiler sucht Units in dieser Reihenfolge:
- Das Verzeichnis der aktuell compilierten Datei
- Alle Verzeichnisse in
–include-path(lyxc –include-path=/my/libs …) - Das Standard-Library-Verzeichnis (automatisch,
std.*-Units)
# Einfacher Build
lyxc main.lyx -o my_app
# Mehrere Include-Pfade
lyxc main.lyx --include-path=./libs --include-path=/opt/lyx/contrib -o my_app
# Alle .lyx-Dateien angeben (bei kleinen Projekten)
lyxc main.lyx db/connection.lyx api/handler.lyx -o my_app
8. Best Practices
Empfehlungen für die Strukturierung von Lyx-Projekten:
| Situation | Empfehlung |
|---|---|
| Namenskollision zwischen Units | Präfix-Konvention einhalten (MyUnit*) |
| Globaler Zustand | Lieber pub fn Get() / pub fn Set() als pub var |
| Zyklische Abhängigkeit | Unit aufteilen — gemeinsame Typen in eine separate types-Unit |
| Große Units (> 500 Zeilen) | In Unterunits aufteilen: mylib.core, mylib.helpers, … |
| Init-Code beim Import | Nicht in Unit-Scope — stattdessen pub fn Init() explizit aufrufen |
| Interne Hilfsfunktionen | Privat lassen — nur was wirklich von außen gebraucht wird mit pub |
→ Vollständige Syntax-Referenz
→ Erste Schritte — erstes Programm
→ Compiler-Parameter
Letzte Aktualisierung: 2026-06-05
