Inhaltsverzeichnis

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.

Pattern Matching · Datentypen · 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 — ganze Zahlen im Bereich 0..4294967295
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:


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.

Ein Tippfehler im Member-Namen ist ein Compile-Fehler: Color.Rrd wird abgewiesen, nicht stillschweigend zu 0.


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:

sema error (line 3): match does not cover variant 'GoAround' — add a case or a wildcard _ => { ... }

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;
        case _                     => 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;
        case _   => 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.

Masken als Konstante

Seit 1.0.20A gelten Enum-Werte auch in con-Ausdrücken und in Startwerten globaler Variablen (#1507). Damit lässt sich eine Maske einmal benennen, statt sie an jeder Prüfstelle neu zusammenzusetzen:

enum P { Read = 1, Write = 2, Exec = 4 }

con MASK: int64 := P.Read as int64 | P.Write as int64;
var perms: int64 := P.Read as int64;

fn main(): int64 {
    PrintLn("MASK=", IntToStr(MASK), "  perms=", IntToStr(perms));
    return 0;
}

MASK=3  perms=1

Die Vorwärtsreferenz ist zulässig — das enum darf unter der con-Zeile stehen, die es benutzt.

<WRAP alert> Vor 1.0.20A ergab genau dieses Muster still 0. Die con-Zeile übersetzte ohne Warnung, MASK war aber 0 — und damit jede Prüfung (wert & MASK) != 0 immer falsch. Wer eine ältere Fassung benutzt, prüft seine Masken nach; der Fehler ist am Quelltext nicht zu sehen. </WRAP>


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

Pattern Matching — match, Guards, Exhaustivität
Datentypen — vollständige Typübersicht
Typ-Aliase und Typumwandlung (as, is)

Letzte Aktualisierung: 2026-08-09

Codebeispiele geprüft: gegen lyxc 1.2.5C übersetzt (Prüflauf 2026-09-08 über die gesamte Doku: 574 Vollprogramme, 0 echte Fehler; zusätzlich 5159 Aufrufe gegen die pub fn-Signaturen in aurum/std gehalten, 0 Abweichungen).