====== Enums — Aufzählungstypen ====== Ein ''enum'' definiert einen Typ, dessen gültige Werte eine abgeschlossene, benannte Menge bilden. Der Compiler kennt alle Werte zur Compile-Zeit — das ist die Grundlage der Exhaustivitätsprüfung in ''match'': Wird ein Enum-Wert nicht behandelt, ist es ein **Fehler**, keine Warnung. Enums sind in Lyx ganzzahlige Typen (intern ''int64'') mit benannten Konstanten. Sie haben keine Methoden und keine Vererbung — ihr einziger Zweck ist die typsichere Zustandsdarstellung. → [[lyx_-_programmiersprache:sprache:pattern-matching|Pattern Matching]] · [[lyx_-_programmiersprache:sprache:datentypen|Datentypen]] · [[lyx_-_programmiersprache:guides:do-178c|DO-178C]] ---- ===== 1. Deklaration ===== // Einfachster Fall: Werte beginnen bei 0 und zählen aufwärts enum Direction { North, South, East, West } // North=0, South=1, East=2, West=3 // Explizite Werte — beliebige int64-Konstanten enum HttpStatus { Ok = 200, Created = 201, NotFound = 404, ServerErr = 500 } // Gemischt: erste Konstante setzt den Startwert, die folgenden zählen weiter enum Priority { Low = 1, Medium, // = 2 High, // = 3 Critical // = 4 } Regeln: * Alle Enum-Werte müssen innerhalb des Gültigkeitsbereichs eindeutig sein. * Werte dürfen sich **nicht** überlappen — ''{ A = 1, B = 1 }'' ist ein Compiler-Fehler. * Enums dürfen leer sein (''enum Empty {}'' — selten sinnvoll, aber erlaubt). ---- ===== 2. Verwendung ===== Ein einfaches Anwendungsbeispiel: enum Color { Red, Green, Blue } // Variablendeklaration var c: Color := Color::Red; // Übergabe als Parameter fn PrintColor(col: Color): void { match (col) { case Color::Red => Print("Rot\n"); case Color::Green => Print("Grün\n"); case Color::Blue => Print("Blau\n"); } } // Rückgabe aus Funktion fn OppositeDirection(d: Direction): Direction { return match (d) { case Direction::North => Direction::South; case Direction::South => Direction::North; case Direction::East => Direction::West; case Direction::West => Direction::East; }; } Der Zugriff auf einen Enum-Wert erfolgt immer mit ''EnumName::Wert'' — der Namespace-Qualifier ist Pflicht. Das verhindert Namenskollisionen zwischen verschiedenen Enums. ---- ===== 3. Enums und match ===== Die Stärke von Enums zeigt sich in Kombination mit ''match'': Der Compiler erzwingt, dass **jeder** mögliche Wert behandelt wird. enum FlightPhase { Preflight, Taxiing, Takeoff, Climbing, Cruise, Descending, Approach, Landing, Rollout } fn PhaseToString(p: FlightPhase): pchar { return match (p) { case FlightPhase::Preflight => "Vor dem Start"; case FlightPhase::Taxiing => "Rollen"; case FlightPhase::Takeoff => "Start"; case FlightPhase::Climbing => "Steigflug"; case FlightPhase::Cruise => "Reiseflug"; case FlightPhase::Descending => "Sinkflug"; case FlightPhase::Approach => "Anflug"; case FlightPhase::Landing => "Landung"; case FlightPhase::Rollout => "Ausrollen"; }; } Wird später ''FlightPhase::GoAround'' hinzugefügt, meldet der Compiler: error: non-exhaustive match — FlightPhase::GoAround not covered --> flight_ctrl.lyx:12:12 hint: add 'case FlightPhase::GoAround =>' or a 'default =>' arm Das ist eine **Sicherheitsgarantie**: Neue Zustände können nicht unbehandelt durchrutschen. ==== Wann default erlaubt ist ==== ''default'' unterdrückt die Exhaustivitätsprüfung. Das ist explizit erlaubt, aber sparsam einsetzen: fn IsErrorStatus(s: HttpStatus): bool { return match (s) { case HttpStatus::ServerErr => true; default => false; // Explizite Entscheidung: alle nicht genannten Werte sind "kein Fehler" // Risiko: neuer Wert wie HttpStatus::GatewayTimeout wird stillschweigend false }; } > In DO-178C DAL-A/B-Code ist ''default'' bei zustandsbehafteten Enums ein Compiler-Fehler wenn ''@dal(A)'' oder ''@dal(B)'' gesetzt ist. Alle Zustände müssen explizit behandelt sein. ---- ===== 4. Enum als Integer ===== Intern ist jeder Enum-Wert ein ''int64''. Die explizite Konvertierung erfolgt mit ''as'': enum HttpStatus { Ok = 200, NotFound = 404, ServerErr = 500 } // Enum → int64 var code: int64 := HttpStatus::Ok as int64; // 200 // int64 → Enum (unsafe: der Compiler prüft den Wert nicht) var s: HttpStatus := 404 as HttpStatus; // In der Praxis: Wert aus Netzwerk empfangen, in Enum konvertieren fn ParseStatus(raw: int64): HttpStatus { return match (raw) { case 200 => HttpStatus::Ok; case 404 => HttpStatus::NotFound; case 500 => HttpStatus::ServerErr; default => HttpStatus::ServerErr; // Fallback bei unbekanntem Code }; } > Die Konvertierung ''intVal as HttpStatus'' ist technisch möglich, aber gefährlich: Der Wert ''999'' wäre ein ungültiger ''HttpStatus''. In ''@dal(A)''-Code ist der direkte Cast von ''int64'' zu einem Enum verboten — stattdessen muss ''ParseStatus'' oder eine vergleichbare Funktion mit explizitem ''match'' verwendet werden. ---- ===== 5. Bit-Flag-Enums ===== Für Bit-Masken werden Enums mit Zweierpotenzen als Werte deklariert und mit Integer-Operatoren kombiniert: enum Permission { Read = 0x01, // Bit 0 Write = 0x02, // Bit 1 Execute = 0x04, // Bit 2 Admin = 0x08 // Bit 3 } // Mehrere Flags kombinieren (als int64 — nicht als Permission) var perms: int64 := Permission::Read as int64 | Permission::Write as int64; // Flag prüfen fn HasPermission(perms: int64, flag: Permission): bool { return (perms & (flag as int64)) != 0; } fn main(): int64 { var p: int64 := Permission::Read as int64 | Permission::Execute as int64; if (HasPermission(p, Permission::Write)) { PrintLn("Schreiben erlaubt"); } else { Print("Kein Schreibzugriff\n"); // Dieser Zweig wird ausgeführt } return 0; } Bit-Flag-Enums werden immer als ''int64'' kombiniert — Lyx bietet keinen speziellen Bitset-Typ. Das ist ein bewusstes Design: Bitoperationen sind explizit und direkt im Code sichtbar. ---- ===== 6. Enums in Datenstrukturen ===== Enums als Felder in Structs und als Array-Elemente: import std.alloc; enum State { Idle, Running, Paused, Stopped } // Enum-Feld in einem alloc'd Puffer (Offset-Muster) pub con TASK_SIZE: int64 := 24; pub con TASK_STATE: int64 := 0; // State als int64 gespeichert pub con TASK_ID: int64 := 8; pub con TASK_PRIO: int64 := 16; fn TaskCreate(id: int64, prio: int64): int64 { var t: int64 := alloc(TASK_SIZE); if (t == 0) { return 0; } poke64(t + TASK_STATE, State::Idle as int64); poke64(t + TASK_ID, id); poke64(t + TASK_PRIO, prio); return t; } fn TaskGetState(t: int64): State { return peek64(t + TASK_STATE) as State; } fn TaskSetState(t: int64, s: State): void { poke64(t + TASK_STATE, s as int64); } fn TaskIsRunning(t: int64): bool { return TaskGetState(t) == State::Running; } ---- ===== 7. Enums in Safety-Code ===== Enums sind ein bevorzugtes Mittel in sicherheitskritischem Code, weil sie den Zustandsraum explizit und abgeschlossen definieren: @flight_crit(DAL-A) enum EngineState { Off = 0, Starting = 1, Idle = 2, Running = 3, Overspeed = 4, Shutdown = 5 } @flight_crit(DAL-A) fn EngineTransition(current: EngineState, cmd: EngineCommand): EngineState { // Vollständige Zustandsmaschine — kein default, alle Kombinationen explizit return match (current) { case EngineState::Off => match (cmd) { ... }; case EngineState::Starting => match (cmd) { ... }; case EngineState::Idle => match (cmd) { ... }; case EngineState::Running => match (cmd) { ... }; case EngineState::Overspeed => EngineState::Shutdown; // immer herunterfahren case EngineState::Shutdown => EngineState::Off; }; } ^ Eigenschaft ^ Enum ^ int64-Konstanten ^ | Compiler-Exhaustivitätsprüfung | ✅ Ja | ❌ Nein | | Typsicherheit im Parameter | ✅ Ja | ❌ Nein (jede int64 passt) | | Dokumentation im Code | ✅ Explizite Namen | Eingeschränkt | | Gültigkeitsbereich | Pro Enum getrennt | Global | | DO-178C geeignet | ✅ Empfohlen für Zustände | Bedingt | ---- ===== 8. Zusammenfassung ===== ^ Frage ^ Antwort ^ | Basistyp | ''int64'' (immer) | | Zugriffssyntax | ''EnumName::Wert'' | | Methoden | Nicht unterstützt | | Enum → int64 | ''val as int64'' | | int64 → Enum | ''intVal as EnumTyp'' (unsafe — Wert unklar) | | match-Exhaustivität | Pflicht ohne ''default'' | | In Safety-Code | Enums für alle Zustände bevorzugen, kein ''default'' | | Bit-Flags | Werte als Zweierpotenzen; kombinieren als ''int64'' | → [[lyx_-_programmiersprache:sprache:pattern-matching|Pattern Matching — match, Guards, Exhaustivität]]\\ → [[lyx_-_programmiersprache:sprache:datentypen|Datentypen — vollständige Typübersicht]]\\ → [[lyx_-_programmiersprache:sprache:typaliase-und-typumwandlung|Typ-Aliase und Typumwandlung (as, is)]] Letzte Aktualisierung: 2026-06-05