Options

Creating and using options

A type foo? is an optional foo.
An option can be empty (have no value inside) or non-empty (have a value inside).

This is useful for values that, in other languages, might be a special value like null or -1.
Explicitly making the value optional means that you won't have to remember that.

main void() info log ().describe info log (1,).describe describe string(a nat?) if x ?= a "non-empty {x}" else "empty"

Above you can see the most common way of using an option: if with ?=.
The unwrapped value of the option becomes x, or if the option was empty, the else branch will run.

These can integrate with other if chains.

main void() info log (() foo "fizz") info log ((1,) foo "fizz") info log ((1,) foo "buzz") foo string(a nat?, b string) if b == "buzz" "buzz" elif x ?= a "{x}" else b

"??" and "||"

The ?? operator provides a default value for an option if it's empty.

main void() info log (() ?? "bar") info log (("crow",) ?? "bar")

The || operator is similar, but it takes two options and returns another option.

main void() info log (() || ()).describe info log (() || (1,)).describe info log ((2,) || (3,)).describe describe string(a nat?) if x ?= a "non-empty {x}" else "empty"

Forcing an option

Use x! to get the value of an option or throw an exception if it is empty.
(Exceptions will be explained in Exceptions.)

main void() empty string? = () non-empty string? = "foo", info log non-empty! info log empty!

Optional calls

In contrast with forcing an option, x?.f calls f only if x is non-empty.

main void() empty string? = () info log "{empty?.reverse}" non-empty string? = "foo", info log "{non-empty?.reverse}" () show string(a string?) a ?? "empty"

You can also use x?[y] to optionally subscript.

main void() empty string[]? = () info log "{empty?[1]}" non-empty string[]? = ("foo", "bar"), info log "{non-empty?[1]}" () show string(a string?) a ?? "empty"

Option conditions

The left hand side of ?= is a destructure. Here _, x destructures a (nat, string).

main void() opt (nat, string)? = (1, "one"), if _, x ?= opt info log x

Other expressions besides if can use option conditions too.
Here's an example with guard:

main void() opt nat? = 1, guard x ?= opt info log "got {x}"

It works in while or until loops too.

main void() x mut nat = 111 until tenth ?= x divide-exact 10 x +:= 1 info log "tenth is {tenth}" x := tenth while half ?= x divide-exact 2 info log "half is {half}" x := half divide-exact nat?(a nat, divisor nat) if a is-multiple-of divisor a / divisor,

For a while loop, the variable is only visible inside the loop.
For an until loop, the variable is only visible after the loop.