====== Funktionen (vertieft) ====== Funktionen sind der zentrale Baustein jedes Lyx-Programms. Diese Seite geht über die Grunddeklaration hinaus und behandelt Tupel-Rückgaben, anonyme Funktionen, Funktionstypen, Higher-Order Functions und den Pipe-Operator. > **''PrintF64'' ist seit lyxc 1.0.17C ein Builtin** (#1254, #1284) — kein Import nötig, auch nicht ''std.io''. Es gibt sechs Nachkommastellen mit abschließendem Zeilenumbruch aus: ''PrintF64(1.25)'' → ''1.250000''. Die Ausgabe rundet sichtbar (''3.14159'' → ''3.141589''); für exakte Stellenzahl ''FloatToStr'' nehmen. > > Ebenfalls in ''std.io'': ''PrintFloatLn(x: f64)'' (mit Umbruch) und ''FloatToStr(val: f64, prec: int64)'' (Zeichenkette, etwa ''%%Print(FloatToStr(3.75, 2))%%'' für Ausgabe ohne Umbruch). → Einführung: [[lyx_-_programmiersprache:erste-schritte|Erste Schritte]] · Syntax: [[lyx_-_programmiersprache:sprache:syntax|Sprachsyntax]] · Methoden: [[lyx_-_programmiersprache:sprache:oop|OOP & Klassen]] · Generics: [[lyx_-_programmiersprache:sprache:generics-traits|Generics & Interfaces]] ---- ===== 1. Grunddeklaration ===== fn Add(a: int64, b: int64): int64 { return a + b; } * Rückgabetyp steht nach dem Doppelpunkt hinter der Parameterliste. * Kein Rückgabewert: Rückgabetyp weglassen (implizit ''void''); ''return'' ohne Wert oder ganz weglassen. * ''pub'' macht eine Funktion aus anderen Units importierbar. // Kein Rückgabewert fn Log(msg: pchar) { PrintLn(msg); } // Öffentlich sichtbar (exportiert) pub fn GetVersion(): pchar { return "1.0.0"; } Alle Funktionen ohne ''pub'' sind privat — sie sind nur innerhalb derselben Unit sichtbar. Das ist die strenge Voreinstellung; explizites Exportieren verhindert unkontrollierte Kopplung zwischen Modulen. ==== Default-Werte für Parameter ==== Ein Parameter kann einen Vorgabewert erhalten. Wird das Argument beim Aufruf weggelassen, setzt der Compiler den Vorgabewert ein. Der Wert muss zur Compile-Zeit feststehen. fn Verbinde(host: pchar, port: int64 = 8080, timeout: int64 = 30): int64 { // ... return 0; } Verbinde("localhost"); // port = 8080, timeout = 30 Verbinde("localhost", 9000); // timeout = 30 Verbinde("localhost", 9000, 5); // alle Werte explizit Benannte Argumente erlauben eine freie Reihenfolge: fn F(a: int64, b: int64 = 5): int64 { return a - b; } F(b: 3, a: 10); // 7 — Reihenfolge frei, weil benannt F(10, b: 3); // 7 — positional und benannt gemischt > **Benannte Argumente und Vorgabewerte lassen sich seit lyxc 1.0.17C kombinieren** (#1252). Ein hinterer Parameter kann einzeln gesetzt werden, der mittlere bleibt auf seiner Vorgabe: > > fn G(a: int64, b: int64 = 2, c: int64 = 3): int64 { return a*100 + b*10 + c; } G(1); // 123 — rein positional, Vorgaben greifen G(1, 5, 9); // 159 G(1, c: 9); // 129 — b bleibt auf 2 G(a: 1, c: 9); // 129 > > Bis 1.0.16x verlangte jeder Aufruf mit benanntem Argument **alle** Parameter (''Parameter ohne Argument im Aufruf von 'G'''). > **Die Signaturprüfung greift auch über Unit-Grenzen** ([[https://github.com/SEOLizer/LyX-Compiler/issues/1264|#1264]], nachgemessen mit lyxc 1.2.2B): ''%%Clamp64(5)%%'' aus ''std.math'' bricht mit ''sema error: falsche Argument-Anzahl im Aufruf von 'Clamp64''' ab. Frühere Fassungen prüften nur freie Funktionen aus derselben Datei. > > **Ungeprüft bleiben die Builtins**: ''%%StrConcat("a")%%'' mit einem statt zwei Argumenten übersetzt weiterhin ohne Meldung — ''StrLen'', ''StrSub'', ''StrCharAt'' und die übrigen eingebauten Namen sind nicht Teil dieser Prüfung. ---- ==== Struct-Parameter: Wert oder Referenz ==== **Ein Struct-Parameter ist ein Wert.** Die Funktion bekommt beim Eintritt eine Kopie; Änderungen daran bleiben in der Funktion. Das entspricht der Zuweisung, die seit 1.0.20A ebenfalls kopiert. Wer das Original des Aufrufers ändern will, sagt das mit ''ref'': type Punkt = struct { x: int64; y: int64; } fn AlsWert(p: Punkt): void { p.x := 99; } // wirkt nur auf die Kopie fn AlsRef(ref p: Punkt): void { p.x := 99; } // wirkt auf das Original fn main(): int64 { var p: Punkt; p.x := 1; AlsWert(p); PrintLn("nach AlsWert: ", IntToStr(p.x)); AlsRef(p); PrintLn("nach AlsRef: ", IntToStr(p.x)); return 0; } nach AlsWert: 1 nach AlsRef: 99 ^ Fall ^ Verhalten ^ | ''fn f(p: T)'' mit Struct ''T'' | Kopie — das Original bleibt unberührt | | ''fn f(ref p: T)'' mit Struct ''T'' | arbeitet auf dem Original | | ''ref'' an einem Skalartyp | **Fehler**: ''ref ist nur bei Struct-Parametern wirksam'' | | Klassen | immer Referenz; ''ref'' ist dort weder nötig noch vorgesehen | ''ref'' ist ein **weiches Schlüsselwort**: es gilt nur unmittelbar vor einem Parameternamen mit folgendem Doppelpunkt. Ein Parameter, der schlicht ''ref'' heißt (''fn F(ref: int64)''), und eine Variable ''var ref := 5'' bleiben zulässig. > **Bis 1.0.20E verhielt sich ein Struct-Parameter umgekehrt** — die Funktion arbeitete auf dem Original, und wer seine Daten behalten wollte, musste vorher selbst kopieren. Code aus dieser Zeit braucht an den betreffenden Stellen jetzt ''ref'', sonst verpufft die Änderung stillschweigend (#1351, #1528). ---- ===== 2. Tupel-Rückgabe — mehrere Werte ===== Funktionen können mehr als einen Wert zurückgeben, indem der Rückgabetyp als Tupel angegeben wird. Das ersetzt Out-Parameter und verhindert, dass Fehlerinformationen über Ausnahmen transportiert werden müssen. ==== Syntax ==== fn Divide(a: int64, b: int64): (int64, bool) { if (b == 0) { return (0, false); } return (a / b, true); } Rückgabetyp: ''(int64, bool)'' — ein Tupel aus zwei Typen.\\ Rückgabewert: ''(Ausdruck1, Ausdruck2)'' — beide Werte in runden Klammern, kommagetrennt. ==== Destrukturierung beim Aufruf ==== unit main; import std.io; import std.string; fn Divide(a: int64, b: int64): (int64, bool) { if (b == 0) { return (0, false); } return (a / b, true); } fn main(): int64 { var result, ok := Divide(10, 3); if (ok) { PrintLn(IntToStr(result)); // 3 PrintLn(""); } // Kurzform ohne explizite Typangabe — Typen werden inferiert var q, ok2 := Divide(7, 0); if (ok2 == false) { PrintLn("Division durch null"); } return 0; } ==== Genau zwei Elemente ==== Ein Tupel trägt **höchstens zwei** Werte — die Aufrufkonvention gibt zwei Register her (''rax'', ''rdx''). Drei Elemente werden abgewiesen: fn Drei(): (int64, int64, int64) { return (1, 2, 3); } // sema error: Tupel mit mehr als zwei Elementen Für mehr Werte ein Struct zurückgeben — das ist ohnehin die lesbarere Form, weil die Felder benannt sind: type Koordinate = struct { lat: f64; lon: f64; valid: bool; }; fn ParseCoord(input: pchar): Koordinate { var k: Koordinate; k.lat := 48.137; k.lon := 11.576; k.valid := true; return k; } Beim Entpacken steht die Form **ohne** Klammern: ''%%var a, b := F();%%''. Die geklammerte Schreibweise ''%%var (a, b) := F();%%'' gibt es nicht. ==== Tupel-Rückgabe vs. struct ==== ^ Situation ^ Empfehlung ^ | Zwei eng zusammengehörige Werte (Ergebnis + Fehlerflag) | Tupel-Rückgabe | | Drei oder mehr Werte | Struct — Tupel tragen nur zwei | | Rückgabe soll benannt und dokumentiert sein | Struct — Feldnamen machen den Code lesbarer | | Temporäres Ergebnis in einer Funktion | Tupel — weniger Overhead als ein Typ zu definieren | ---- ===== 3. Anonyme Funktionen ===== Lyx erlaubt Funktionsliterale — also Funktionen ohne Namen, die direkt als Ausdruck geschrieben werden. Sie folgen der gleichen Syntax wie benannte Funktionen, tragen aber keinen Bezeichner. ==== Syntax ==== fn(param1: Typ1, param2: Typ2): RückgabeTyp { return ...; } ==== Inline als Argument ==== import std.io; fn Apply(value: int64, transform: fn(int64): int64): int64 { return transform(value); } fn main(): int64 { var result: int64 := Apply(21, fn(x: int64): int64 { return x * 2; }); PrintLn(IntToStr(result)); // 42 PrintLn(""); return 0; } ==== Als Variable speichern ==== Eine anonyme Funktion kann mit ''let'' oder ''var'' gebunden werden: unit main; import std.io; import std.string; fn main(): int64 { let double: fn(int64): int64 := fn(x: int64): int64 { return x * 2; }; let greet: fn(pchar): void := fn(name: pchar): void { PrintLn(StrConcat("Hallo, ", name)); }; PrintLn(IntToStr(double(21))); // 42 greet("Lyx"); // Hallo, Lyx return 0; } > **Lambda an einem ausgeschriebenen ''fn''-Typ arbeitet seit lyxc 1.0.17C** (#1249). ''%%Apply(21, fn(x: int64): int64 { return x * 2; })%%'' liefert 42 — vorher stürzte genau diese Verbindung ohne Meldung ab (SIGSEGV). > > **Anonyme Funktionen dürfen auch auf Modulebene stehen** ([[https://github.com/SEOLizer/LyX-Compiler/issues/1589|#1589]] behoben). ''%%let double: fn(int64): int64 := fn(x: int64): int64 { return x * 2; };%%'' übersetzt außerhalb jeder Funktion und liefert mit 1.1.2E ''double(21) = 42''; vorher meldete das ''codegen error: globale Variable 'double': Startwert ist zur Uebersetzungszeit nicht bekannt''. > > Ein Verweis auf eine **benannte** Funktion geht global ebenfalls — mit ''let'', ''var'' und seit [[https://github.com/SEOLizer/LyX-Compiler/issues/1589|#1589]] auch mit ''con''. Globale Variablen vom Funktionstyp sind seit [[https://github.com/SEOLizer/LyX-Compiler/issues/1574|#1574]] in beiden Formen benutzbar (mit und ohne Startwert). > **Zum Erfassen der Umgebung:** Anonyme Funktionen greifen auf Variablen des umgebenden Scope zu — anders als frühere Fassungen dieser Seite behaupteten. Der Wert wird dabei **zum Definitionszeitpunkt** übernommen; eine spätere Änderung wirkt nicht mehr: > > var n: int64 := 100; var f := fn(x: int64): int64 { return x + n; }; n := 1; f(5); // 105, nicht 6 > > Für Safety-kritischen Code (DO-178C, MISRA) bleibt die Empfehlung, Zustand ausdrücklich als Parameter zu übergeben — die versteckte Abhängigkeit besteht hier real, sie wird nur nicht verhindert. ---- ===== 4. Funktionstypen ===== Ein Funktionstyp beschreibt die Signatur einer Funktion — welche Parameter sie nimmt und welchen Typ sie zurückgibt. Mit ''type'' lässt sich ein benannter Alias für einen Funktionstyp anlegen. ==== Syntax ==== type TypName = fn(Param1Typ, Param2Typ): RückgabeTyp; ==== Beispiele ==== // Vergleichsfunktion für zwei int64-Werte — gibt Ordnung zurück type Comparator = fn(a: int64, b: int64): int32; // Transformationsfunktion: int64 → int64 type Transformer = fn(value: int64): int64; // Ereignis-Handler ohne Rückgabewert type EventHandler = fn(event_id: int32, data: int64): void; > **Bruch seit 1.0.x — die Aufrufkonvention für ''fn''-Zeiger** ([[https://github.com/SEOLizer/LyX-Compiler/issues/1274|#1274]]). Betroffen ist nur, wer einen ''fn''-Zeiger aus einer **rohen Maschinencode-Adresse** baut; wer Funktionen und Lambdas ganz normal übergibt, merkt nichts. Der Compiler meldet hier nichts, und alter Code übersetzt weiterhin. > > Bis 0.9.x war ein ''fn''-Zeiger ein **Closure-Deskriptor**: der Wert zeigte auf einen Zwei-Wort-Block (''[fp+0]'' = Codeadresse, ''[fp+8]'' = Umgebung), der Aufruf übergab die Umgebung in ''rdi'' und schob die deklarierten Argumente nach ''rsi'', ''rdx'', … > > Seither **ist** der Wert die Codeadresse, und die deklarierten Argumente folgen SysV unmittelbar: > > var f: fn(int64,int64): int64 := adresse as fn(int64,int64): int64; f(a, b); // a landet in rdi, b in rsi > > Handgeschriebener Maschinencode, der die Argumente noch aus ''rsi''/''rdx'' liest — Kontextwechsel, Scheduler-Primitive, Fences in LyxOS —, läuft nach dem Wechsel weiter und liest die **falschen Register**. Eine Compiler-Warnung an der ''as''-Umwandlung gäbe es dafür nicht: sie träfe genau die legitime Schreibweise und sagte nichts darüber, welche Konvention der Zielcode erwartet. Benannte Typen verbessern die Lesbarkeit von Parameterlisten erheblich: // Ohne Alias — schwer zu lesen fn Sort(arr: int64, n: int64, cmp: fn(int64, int64): int32): void { ... } // Mit Alias — sofort klar type Comparator = fn(a: int64, b: int64): int32; fn Sort(arr: int64, n: int64, cmp: Comparator): void { ... } Benannte Funktionen können überall dort übergeben werden, wo ein passender Funktionstyp erwartet wird — einfach durch Angabe des Namens ohne ''()'': unit main; import std.io; import std.string; type Comparator = fn(a: int64, b: int64): int32; fn CompareAsc(a: int64, b: int64): int32 { if (a < b) { return -1; } if (a > b) { return 1; } return 0; } fn CompareDesc(a: int64, b: int64): int32 { return CompareAsc(b, a); // Reihenfolge getauscht } fn main(): int64 { var cmp: Comparator := CompareAsc; // Funktion als Wert PrintLn(IntToStr(cmp(3, 7) as int64)); // -1 cmp := CompareDesc; PrintLn(IntToStr(cmp(3, 7) as int64)); // 1 return 0; } ---- ===== 5. Higher-Order Functions ===== Eine Higher-Order Function (HOF) ist eine Funktion, die eine andere Funktion als Parameter entgegennimmt oder eine Funktion als Ergebnis zurückgibt. ==== Funktion als Parameter ==== Der Parameter wird mit dem Präfix ''fn'' und dem Funktionstyp deklariert: fn paramName: fn(ArgTyp): RückgabeTyp import std.io; // Apply: wendet transform auf value an und gibt das Ergebnis zurück fn Apply(value: int64, transform: fn(int64): int64): int64 { return transform(value); } // Für jeden Index in [0, n) callback aufrufen fn ForEach(n: int64, callback: fn(int64): void): void { var i: int64 := 0; while (i < n) limit(1000000) { callback(i); i := i + 1; } } // Akkumuliert f(i) für alle i in [0, n) fn Accumulate(n: int64, initial: int64, fold: fn(int64, int64): int64): int64 { var acc: int64 := initial; var i: int64 := 0; while (i < n) limit(1000000) { acc := fold(acc, i); i := i + 1; } return acc; } fn Square(x: int64): int64 { return x * x; } fn PrintIdx(i: int64): void { Print(IntToStr(i)); Print(" "); } fn Sum(acc: int64, val: int64): int64 { return acc + val; } fn main(): int64 { PrintLn(IntToStr(Apply(7, Square))); // 49 PrintLn(""); ForEach(5, PrintIdx); // 0 1 2 3 4 PrintLn(""); PrintLn(IntToStr(Accumulate(5, 0, Sum))); // 0+1+2+3+4 = 10 PrintLn(""); return 0; } ==== HOF mit Generics ==== Funktionsparameter lassen sich mit Generics kombinieren: fn MapApply(value: In, transform: fn(In): Out): Out { return transform(value); } fn main(): int64 { var doubled: int64 := MapApply(21, fn(x: int64): int64 { return x * 2; }); PrintLn(IntToStr(doubled)); // 42 PrintLn(""); return 0; } → Ausführliche Generics-Syntax: [[lyx_-_programmiersprache:sprache:generics-traits|Generics & Interfaces]] ==== Dispatch-Tabelle ==== Funktionstypen lassen sich in Arrays speichern — das ist das Lyx-Äquivalent einer vtable ohne Klassen: type Handler = fn(data: int64): void; fn OnConnect(data: int64): void { Print("connect\n"); } fn OnDisconnect(data: int64): void { Print("disconnect\n"); } fn OnMessage(data: int64): void { Print("message\n"); } con CONNECT: int64 := 0; con DISCONNECT: int64 := 1; con MESSAGE: int64 := 2; fn main(): int64 { var dispatch: [3]Handler := [OnConnect, OnDisconnect, OnMessage]; var event: int64 := MESSAGE; if (event >= 0 & event < 3) { var h: Handler := dispatch[event]; // erst in eine Variable h(0); // dann aufrufen -> message } return 0; } > **Der Aufruf muss über eine Zwischenvariable gehen.** ''dispatch[event](0)'' direkt ist ein Parse-Fehler: ''Aufruf ueber einen indizierten Ausdruck wird nicht unterstuetzt'' (#1505). Dasselbe gilt für Feldzugriffe. Der Wert wird also erst einer Variablen des Funktionstyps zugewiesen und diese dann aufgerufen — inhaltlich derselbe Sprung, nur eine Zeile mehr. ==== Funktionen an Threads übergeben ==== ''std.thread'' erwartet den Funktionszeiger als ''int64''. Das ist die einzige Ausnahme von der typisierten Übergabe — es liegt an der C-POSIX-Schnittstelle unter der Haube: import std.thread; import std.io; fn Worker(arg: int64): int64 { PrintLn("Thread läuft"); return 0; } fn main(): int64 { var t: Thread := ThreadCreate(Worker as int64, 0); ThreadJoin(t); return 0; } → Vollständige Thread-Dokumentation: [[lyx_-_programmiersprache:sprache:threads|Threads & Nebenläufigkeit]] ---- ===== 6. Pipe-Operator ===== Der Pipe-Operator ''|>'' leitet den Wert auf der linken Seite als **erstes Argument** an die Funktion auf der rechten Seite weiter. Er macht Transformationsketten ohne verschachtelte Klammern lesbar. ==== Syntax ==== wert |> Funktion() // entspricht: Funktion(wert) wert |> Funktion(?, arg) // entspricht: Funktion(wert, arg) wert |> Funktion(arg, ?) // entspricht: Funktion(arg, wert) Der Platzhalter ''?'' benennt die Stelle, an die der gepipte Wert eingesetzt wird. Bei einer Funktion **ohne** weitere Argumente kann die Klammer leer bleiben. > **Seit lyxc 1.0.17C setzt ''%%|>%%'' den Wert auch ohne Platzhalter ein** (#1253): ''%%50 |> Clamp(0, 30)%%'' liefert ''30'', der linke Wert wird erstes Argument. Der ausdrückliche Platzhalter ''%%50 |> Clamp(?, 0, 30)%%'' bleibt gültig und ist die deutlichere Schreibweise, sobald der Wert **nicht** an die erste Stelle soll. Bis 1.0.16x scheiterte die Form ohne ''?'' an der Argumentzahl. ==== Beispiel: Wert-Transformation ==== import std.math; import std.io; fn Clamp(val: f64, lo: f64, hi: f64): f64 { if (val < lo) { return lo; } if (val > hi) { return hi; } return val; } fn main(): int64 { // Ohne Pipe — schwer zu lesen bei tiefer Schachtelung var r1: f64 := RoundF64(Clamp(AbsF64(-3.7), 0.0, 3.0)); // Mit Pipe — Datenfluss von links nach rechts var r2: f64 := -3.7 |> AbsF64() |> Clamp(?, 0.0, 3.0) |> RoundF64(); PrintF64(r1); // 3.7 → Abs → 3.7 → Clamp → 3.0 → Round → 3.0 PrintLn(""); PrintF64(r2); // identisch PrintLn(""); return 0; } ==== Pipe mit HOF ==== fn Double(x: int64): int64 { return x * 2; } fn Negate(x: int64): int64 { return -x; } fn IsEven(x: int64): bool { return x % 2 == 0; } fn main(): int64 { var v: int64 := 5 |> Double() |> Negate(); // -10 if (10 |> IsEven()) { PrintLn("gerade"); } return 0; } ---- ===== 7. Sichtbarkeit und Modifizierer ===== ^ Modifizierer ^ Position ^ Bedeutung ^ | ''pub'' | Vor ''fn'' | Exportiert die Funktion — aus anderen Units importierbar | | ''@inline'' | Vor ''fn'' | Compiler soll die Funktion inline expandieren | | ''@no_opt'' | Vor ''fn'' | Keine Optimierungen — für Benchmarks, MMIO-Debugging | | ''@extern'' | Vor ''fn'' | Externe C-Funktion ohne Implementierung in Lyx | | ''@variadic'' | Zusätzlich zu ''@extern'' | Variadische Argumentliste im C-Stil | // Exportierte Hilfsfunktion pub fn Clamp(val: int64, lo: int64, hi: int64): int64 { if (val < lo) { return lo; } if (val > hi) { return hi; } return val; } // Einfache Funktionen inlinet der Codegen selbst; ein Attribut dafuer gibt es nicht fn Abs(x: int64): int64 { if (x < 0) { return -x; } return x; } // Externe C-Funktion — extern fn mit link-Klausel, kein @extern-Attribut extern fn strlen(s: pchar): int64 link "libc.so.6"; > ''@inline'', ''@noinline'', ''@extern'' und ''@variadic'' sind **keine Attribute** dieser Sprache — der Compiler weist sie mit ''unbekanntes Attribut'' ab. Externe Funktionen werden mit ''extern fn … link "<bibliothek>"'' deklariert (→ [[lyx_-_programmiersprache:sprache:ffi|FFI]]); über das Inlining entscheidet der Codegen. → Alle Attribute: [[lyx_-_programmiersprache:sprache:attributes-pragmas|Attribute & Pragmas]] · FFI: [[lyx_-_programmiersprache:sprache:ffi|C-Interoperabilität]] ---- ===== 8. Vollständiges Beispiel: Auswertungs-Pipeline ===== Das folgende Beispiel kombiniert Tupel-Rückgabe, Funktionstypen und Higher-Order Functions in einem realistischen Muster: import std.io; import std.math; // Funktionstypen type Validator = fn(value: f64): bool; type Transform = fn(value: f64): f64; // Gibt (transformierterWert, erfolgreich) zurück fn Process(value: f64, validate: Validator, transform: Transform): (f64, bool) { if (validate(value) == false) { return (0.0, false); } return (transform(value), true); } // Konkrete Implementierungen fn IsPositive(v: f64): bool { return fGt(v, 0.0); } fn Normalize(v: f64): f64 { return fDiv(v, 100.0); } fn main(): int64 { var inputs: [4]f64 := [42.0, -5.0, 150.0, 0.0]; var i: int64 := 0; while (i < 4) limit(4) { var out, ok := Process(inputs[i], IsPositive, Normalize); if (ok) { Print("OK: "); PrintF64(out); Print("\n"); } else { Print("UNGUELTIG: "); PrintF64(inputs[i]); Print("\n"); } i := i + 1; } return 0; } Ausgabe: OK: 0.420000 UNGUELTIG: -5.000000 OK: 1.500000 UNGUELTIG: 0.000000 > **Funktionsparameter tragen kein ''fn'' vor dem Namen.** Frühere Fassungen zeigten ''fn validate: Validator'' — das ist ein Parse-Fehler (''expected IDENT, got fn''). Der Parametername steht wie bei jedem anderen Typ direkt vor dem Doppelpunkt: ''validate: Validator''. ---- ===== Zusammenfassung ===== ^ Konzept ^ Syntax ^ Beispiel ^ | Einfache Funktion | ''fn Name(p: T): R { return ...; }'' | ''fn Add(a: int64, b: int64): int64'' | | Kein Rückgabewert | Rückgabetyp weglassen | ''fn Log(msg: pchar)'' | | Exportiert | ''pub fn ...'' | ''pub fn GetVersion(): pchar'' | | Tupel-Rückgabe | '': (T1, T2)'' | ''fn Divide(...): (int64, bool)'' | | Destrukturierung | ''var a, b := Fn(...)'' | ''var result, ok := Divide(10, 3)'' | | Anonyme Funktion | ''fn(p: T): R { return ...; }'' | direkt als Argument | | Funktionstyp-Alias | ''type F = fn(T): R'' | ''type Comparator = fn(int64, int64): int32'' | | HOF-Parameter | ''name: fn(T): R'' | ''fn Apply(v: int64, f: fn(int64): int64)'' | | Pipe-Operator | ''wert %%|%%> Fn(args)'' | ''-3.7 %%|%%> Abs() %%|%%> Round()'' | | Funktion als Wert | Name ohne ''()'' | ''var f: Comparator := CompareAsc'' | ---- Letzte Aktualisierung: 2026-09-05 ([[https://github.com/SEOLizer/LyX-Compiler/issues/1264|#1264]], nachgemessen mit lyxc 1.2.2B) — Kasten präzisiert: importierte Funktionen werden geprüft, Builtins nicht. Vorherige letzte Aktualisierung: 2026-08-30 — Aufrufkonvention für ''fn''-Zeiger ergänzt (#1274, Bruch gegenüber 0.9.x). Vorherige 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).