LEVIATHAN v962456e · 962456eee1

leviathan-lang.com / docs / learn

No null: optionals

Absence as a typed value, the ?? and ?. operators, and narrowing by flow typing.

Absence is a value

Leviathan has no null. Absence is a real, typed value called None, and T? is simply sugar for the union T | None. Because absence is in the type, the compiler makes you handle it. You cannot quietly forget.

A value that may be absent

string? header(string name) => name == "Authorization" ? "secret" : None;

string? token = header("Authorization");   // maybe there, maybe not
// token.length();   // compile error: must handle the None case first
console.writeln(token ?? "none");
console.writeln(header("Cookie") ?? "none");
secret
none

Defaults and short-circuits

Two operators cover the common cases. ?? supplies a default when a value is None; ?. short-circuits a call or access to None.

?? and ?.

string? token = "abc";
string? missing = None;
string shown = token ?? "anonymous";     // fall back to a default
string other = missing ?? "anonymous";
int? len     = token?.length();          // None if token is None
int? none    = missing?.length();
console.writeln(shown);
console.writeln(other);
console.writeln(len);
console.writeln(none);
abc
anonymous
3
None

Narrowing by flow typing

For anything richer, narrow by flow typing. Once you have checked, the compiler tracks that the value is present inside that branch, including across && and along member paths.

Narrowing with != None

string? token = "abc";
if (token != None && token.length() > 0) {
    console.writeln("authorized: ${token}");   // token is a plain string here
} else {
    console.writeln("no credentials");
}

string? missing = None;
if (missing != None && missing.length() > 0) {
    console.writeln("authorized: ${missing}");
} else {
    console.writeln("no credentials");
}
authorized: abc
no credentials

Conditions must be bool: there is no "truthiness." An empty string, a zero, and None are all distinct and none of them is secretly false. The reference entry on unions and optionals has the full narrowing rules.

See also

  • Unions and optionals — Closed unions T | U, the optional T?, narrowing with != None and is, and the ?? and ?. operators.