Null-Sicherheit und Result-Typ: Fehler als Werte behandeln
Kurz: Moderne Sprachen machen „kein Wert“ und „Fehler“ im Typ sichtbar (Option, Result, nullable Typen), sodass der Compiler vergessene Prüfungen erkennt, statt dass es zur Laufzeit knallt.
Genauer: Der Erfinder der Null-Referenz, Tony Hoare, nannte sie seinen „Milliarden-Dollar-Fehler“: Fast jeder Wert kann plötzlich null sein, und vergessene Prüfungen führen zu NullPointerException und TypeError. Neuere Sprachen modellieren das Fehlen im Typsystem.
Im Detail
Optional / nullable Typen
- Kotlin:
Stringkann nie null sein,String?schon. Der Compiler zwingt zur Prüfung:name?.length,name ?: "unbekannt". - TypeScript (
strictNullChecks):string | undefined, Aufruf mit?.und??. - Swift:
String?(Optional),if let,guard let. - Rust:
Option<T>mitSome(x)oderNone; kein null. - Java:
Optional<T>, Annotationen (@Nullable), Werkzeuge wie NullAway. - C#: Nullable Reference Types (
string?). Der Fehler wird vom Compiler entdeckt, nicht erst im Betrieb.
Result-Typ statt Ausnahmen
Statt Ausnahmen zu werfen, liefern Funktionen einen Wert, der Erfolg oder Fehler enthält:
fn teile(a: f64, b: f64) -> Result<f64, String> {
if b == 0.0 { Err("Division durch null".to_string()) }
else { Ok(a / b) }
}
match teile(1.0, 0.0) {
Ok(x) => println!("{}", x),
Err(e) => println!("Fehler: {}", e),
}Result gibt es in Rust, Swift, Kotlin (Result), Scala (Either), Haskell (Either) und kann in anderen Sprachen als Bibliothek nachgebaut werden. Der Fehlerweg ist im Typ sichtbar und nicht ignorierbar.
Vor- und Nachteile
Vorteile: Sicherheit (Compiler prüft), Lesbarkeit (erwartbare Fehler stehen in der Signatur), keine versteckten Sprünge wie bei Ausnahmen, gut verkettbar (map, and_then, ?-Operator). Nachteile: mehr Schreibaufwand, Verschachtelung ohne gute Syntax, für unerwartete Fehler (Speicher voll, Programmfehler) bleiben Ausnahmen oder Panics sinnvoll. Faustregel: erwartbare Fehler als Werte, Programmierfehler als Ausnahmen/Abbruch.
In der Praxis
Auch ohne neue Sprache: Eingaben früh prüfen, None/null nicht herumreichen, sinnvolle Standardwerte oder „Null-Objekt“-Muster nutzen, Typen genau wählen (int statt int|null), in TypeScript strict aktivieren. Dokumentiere, wann eine Funktion nichts liefern kann.
Siehe auch: NullPointerException, Exception Handling, Cannot read properties of undefined, Typsysteme