Skip to main content

optional

A value that is either present or absent: Optional<T> holds some(v) or none.

const callsign: Optional<string> = some("Viper-1");
const no_track: Optional<uint32> = none;

Values​

Optional< and > are fixed syntactic wrappers rather than a general type constructor.

  • some(expr) has type Optional<T> for an expr of type T.
  • none takes its T from context: a declared type, a parameter type, or an ascription. A none with none of those is ambiguous.
  • Optionals nest, and the closing > of an inner one is its own token, so Optional<Optional<bit>> closes correctly.
  • Two optional types are assignable when their inner types are.
const nested: Optional<Optional<bit>> = some(some(true));

function safe_divide(a: float64, b: float64) -> Optional<float64> =
    if b == 0.0 then none else some(a / b);

Reading the value back​

An optional is opened by naming both cases. Nothing implicitly unwraps one.

  • A match covers an optional with a some(x) pattern and a none pattern.
  • getOrElse(x, fallback) returns the contained value or the fallback, whose type must be the inner type.
  • try(expr) produces Optional<T> from an expression that may fail at runtime, so a caught failure arrives as none.
  • map accepts an optional as its source as well as an array.
const callsign: Optional<string> = some("Viper-1");
const no_track: Optional<uint32> = none;

getOrElse(callsign, "unknown")                                  // => "Viper-1"
getOrElse(no_track, 0)                                          // => 0
match (callsign) { some(name) => name; none => "unknown"; }     // => "Viper-1"
try((100: int32) / 0)                                           // => none

Errors​

A payload of the wrong type​

const callsign: Optional<string> = some(7);   // error: type-mismatch

An absent value with no type to be absent of​

A const always carries a type, so a context-less none surfaces on an inferred binding instead. A binding the declared return type reaches is pinned by it; this one is not.

function callsign(id: uint32) -> string = {
    let missing = none;   // error: ambiguous-inferred-type
    "unknown";
};

A fallback that is not the inner type​

const no_track: Optional<uint32> = none;

const track: uint32 = getOrElse(no_track, "none");   // error: builtin-call-args

An optional where the inner type is expected​

const callsign: Optional<string> = some("Viper-1");

const name: string = callsign;   // error: type-mismatch
  • match — the form that covers both cases.
  • primitives — the inner types an optional usually wraps.