Skip to content

Option

Represent absence with Some, None, optional types, patterns, safe access, and fallback.

Updated View as Markdown

Option[T] contains either Some(T) or None.

selected: Option[string] = Some("Atoll")
missing: Option[string] = None

T? is equivalent and is the preferred compact spelling.

selected: string? = Some("Atoll")
missing: string? = None

Absence

Atoll has no null keyword. A value can be absent only when its type admits absence.

name: string = None  // error
name: string? = None // valid

Nested optionals are distinct.

outer: string?? = None

string?? is Option[Option[string]]; it can distinguish no outer result from an outer result containing no string.

Construction

Use Some(value) and None explicitly.

port: int? = Some(8080)

An expected optional type can also lift a compatible bare value.

port: int? = 8080

The expected type is important for None, because the variant itself does not identify T.

Match

Match when both cases carry meaningful behavior.

match users.get(0) {
    Some(user) => show(user)
    None => show_empty_state()
}

The checker requires both cases unless an earlier pattern or wildcard covers the remainder.

Conditional patterns

Use an if pattern for one successful branch.

if Some(user) := cache.get(id) {
    show(user)
} else {
    load(id)
}

Use a refutable binding with else when the payload must remain in scope after the check.

Some(user) := cache.get(id) else {
    return None
}

return Some(user.name)

The failure block must diverge.

Safe access

?. accesses a field or method only for Some.

city := account?.profile?.city

The result remains optional. If any receiver in the chain is None, the whole chain produces None.

This differs from postfix propagation ?, which exits the enclosing optional function on None.

Fallback

?? extracts a payload or lazily evaluates a fallback.

name := configured_name ?? "anonymous"

The right side runs only when the left is None.

??= fills a mutable optional place only when it is absent.

mut label: string? = None
label ??= compute_label()

The total methods unwrap_or and unwrap_or_else provide equivalent eager or lazy fallback APIs.

unwrap_or(default) evaluates default before the call. unwrap_or_else invokes its zero-argument closure only for None. Prefer the latter when the fallback is expensive or effectful.

Transformations

Use map to transform a present value while preserving absence.

upper := maybe_name.map { name => name.to_upper_case() }

Use flat_map when the callback already returns Option.

email := maybe_user.flat_map { user => user.primary_email }

Filtering retains a payload only when a predicate holds.

positive := maybe_number.filter { value => value > 0 }

Conversion

to_result(error) converts absence into a typed failure.

user := maybe_user.to_result(NotFound { id })?

Some(value) becomes Ok(value); None becomes Err(error).

The error argument to to_result is an ordinary call argument and is therefore evaluated before the method runs. Use an explicit match when constructing that error must itself be lazy.

to_list() maps Some(value) to a one-element list and None to an empty list. flatten() removes one optional layer.

Propagation

Postfix ? extracts Some and returns None from a compatible optional function.

fn first_name(users: []User): string? {
    user := users.get(0)?
    return user.name
}

It does not convert None into an arbitrary Result error. Perform that conversion explicitly with to_result.

Representation

The compiler may niche-pack an optional reference-shaped value or use an explicit tag for an inline scalar/aggregate. That representation does not change the source cases: every Option[T] is still exactly Some(T) or None.

Code must not infer presence from a raw address, integer value, or storage layout. Pattern matching and the documented methods are the portable way to observe the tag.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close