Skip to content
CryoCryo home
Stdlibcore

option

import std::core::option; — in the prelude · source

Types

Option<T>

type enum Option<T> {
    Some(T);
    None;
}

implement enum Option<T> {
    is_some(&this) -> boolean;
    is_none(&this) -> boolean;
    as_ref(&this) -> Option<T*>;
    unwrap_ptr(&this) -> T*;
    ![sink]
    unwrap(&this) -> T;
    ![sink]
    expect(&this, message: string) -> T;
    ![sink]
    unwrap_or(&this, default_value: T) -> T;
    ![sink]
    unwrap_or_else(&this, default_fn: () -> T) -> T;
    ![sink]
    map<U>(&this, f: (T) -> U) -> Option<U>;
    ![sink]
    and_then<U>(&this, f: (T) -> Option<U>) -> Option<U>;
    ![sink]
    or_else(&this, f: () -> Option<T>) -> Option<T>;
    take(mut &this) -> Option<T>;
    ![sink]
    ok_or<E>(&this, err: E) -> Result<T, E>;
    ![sink]
    ok_or_else<E>(&this, err_fn: () -> E) -> Result<T, E>;

    contains(&this, value: &T) -> boolean
    where T: Eq;
}

Option<T> is how Cryo says "there might not be a value here". It replaces the nullable pointer: the compiler will not let you reach the payload without handling the absent case.

match (maybe_port) {
    Option::Some(p) => { println(f"port {p}"); }
    Option::None    => { println("no port configured"); }
}

The ![sink] attribute marks the methods that consume the receiver: after opt.unwrap() the move-checker treats opt as moved, even though the parameter is spelled &this. The unmarked methods leave the receiver live.

Variants

Variant
Some(T)
None

Methods

is_some(&this) -> boolean;
is_none(&this) -> boolean;
as_ref(&this) -> Option<T*>;

Borrow the contained value in place: Some(v) -> Some(&v), None -> None. The pointer aliases the receiver's payload (no copy is made), so unlike the consuming accessors this is NOT ![sink] - the receiver stays live and keeps ownership of T. The pointer is valid only while the receiver outlives it and is invalidated by anything that moves or overwrites the receiver.

unwrap_ptr(&this) -> T*;

Borrow the contained value in place, aborting on None. Like as_ref the pointer aliases the receiver's payload rather than copying it, so the receiver keeps ownership of T and this is NOT ![sink]; the pointer is invalidated by anything that moves or overwrites the receiver.

![sink] unwrap(&this) -> T;

Return the inner value, aborting on None. Prefer unwrap_or or a match in code that must not panic.

![sink] expect(&this, message: string) -> T;

Like unwrap, but with a caller-supplied message describing the invariant the caller believed held.

![sink] unwrap_or(&this, default_value: T) -> T;
![sink] unwrap_or_else(&this, default_fn: () -> T) -> T;

Use this when the default is expensive and shouldn't be computed in the Some case.

![sink] map<U>(&this, f: (T) -> U) -> Option<U>;
![sink] and_then<U>(&this, f: (T) -> Option<U>) -> Option<U>;

Monadic bind: chain operations each of which may be absent.

![sink] or_else(&this, f: () -> Option<T>) -> Option<T>;
take(mut &this) -> Option<T>;

Replace with None and return the previous value.

![sink] ok_or<E>(&this, err: E) -> Result<T, E>;

Some(v) -> Ok(v); None -> Err(err).

![sink] ok_or_else<E>(&this, err_fn: () -> E) -> Result<T, E>;
contains(&this, value: &T) -> boolean where T: Eq;

True if the option is Some(x) where x.equals(&value).

Querying and unwrapping

unwrap panics on None and expect panics with your message; unwrap_or takes a fallback value and unwrap_or_else computes one only when needed.

Borrowing without consuming

unwrap and friends take the value out. When the payload owns heap storage and you only want to look at it, borrow instead:

  • as_ref(&this) -> Option<T*> — Some(v) becomes Some(&v), None stays None. The pointer aliases the receiver's payload rather than copying it, so the receiver keeps ownership.
  • unwrap_ptr(&this) -> T* — the same borrow, aborting on None, and one less layer to unwrap.

Both pointers are invalidated by anything that moves or overwrites the receiver.

Transforming

map, and_then, and or_else chain computations without unwrapping. take() replaces the receiver with None and returns what was there. ok_or and ok_or_else turn the absent case into an Err.

The ?? operator is sugar over the same idea: opt ?? fallback yields the payload or fallback, evaluating the fallback only on None.

Trait implementations

implement<T> trait Clone for enum Option<T> where T: Clone
implement<T> trait Eq for enum Option<T> where T: Eq
implement<T> trait Display for enum Option<T> where T: Display
std::fmt::display
implement<T> trait Debug for enum Option<T> where T: Debug
std::fmt::display

Display and Debug both render Some(...) / None; the difference is which trait the payload goes through.