Optional values
Option values are created using the Option
type, defined in the std::option
module. The Option
type is an object that can either wrap a value, in which
case it's called a "Some", or signal the lack of a value, in which case it's
called a "None". You can create such values as follows:
Option.some(10)
Option.none
The type signature of an Option
is Option!(T)
where T
is the type that's
wrapped when present. Since the Option
type is such a commonly used type, Inko
provides syntax sugar to safe you some typing: ?T
. It's recommended that you
use ?T
instead of Option!(T)
.
Getting Option values
An Option
is its own object that wraps a value (if present). To use that
value, you must explicitly get it from the wrapping Option
. You can do this
using Option.get
:
let x = Option.some(10)
x.get # => 10
This method panics when used on a "None". There are two methods you can use to
provide a default value, in case the Option
is a "none":
Option.get_or
Option.get_or_else
The method get_or
takes an argument, evaluates it, and returns it if the
Option
is a "None". The method get_or_else
takes a closure, and evaluates it
when the Option
is a "None":
Option.none.get_or(0) # => 0
Option.none.get_or_else { 0 } # => 0
If the default value is already defined (e.g. it's just a variable), it's
recommended to use get_or
. If the default should only be evaluated if the
Option
is a "None", the use of get_or_else
is recommended. For example, if
the default value is the contents of a file that has yet to be read, it's best
to use get_or_else
instead of get
.
Mapping Option values
Sometimes an Option
needs to be converted into another Option
, such as
converting a Option!(Integer)
into an Option!(String)
. This can be done
using Option.map
and Option.then
.
Option.map
takes a closure that returns a value. If the Option
is a "Some",
Option.map
returns a new Option
wrapping the returned value. If the Option
is a "None", another "None" is returned:
Option.some(10).map do (num) { num * 2 } # => Option.some(20)
Option.none.map do (num: Integer) { num * 2 } # => Option.none
Option.then
is similar, except its closure returns an Option
. For a "Some",
that Option
is returned, otherwise a "None" is returned:
Option.some(10).then do (num) { Option.some(num * 2) } # => Option.some(20)
Option.none.then do (num: Integer) { Option.some(num * 2) } # => Option.none
Comparing Option values
The Option
type implements the Equal
trait, allowing you to compare it to
other Option
objects that wrap a value of the same type:
Option.some(10) == Option.some(10) # => True
Option.some(10) == Option.some(20) # => False
Option.some(10) == Option.none # => False
Option truthyness
An Option
is considered to be True if it's a "Some", otherwise it's considered
as False:
Option.some(10).if(true: { 10 }, false: { 20 }) # => 10
Option.none.if(true: { 10 }, false: { 20 }) # => 20