Optional Values with ard/maybe
The ard/maybe module provides functions for working with optional values. The Maybe type (written as T?) represents a value that may or may not be present.
The maybe module provides:
- Value creation with
maybe::some()andmaybe::none() - Nullable types for safe representation of optional values
- Type safety to prevent null pointer errors at compile time
use ard/maybeuse ard/io
fn main() { let maybe_name: Str? = maybe::some("Alice")
match maybe_name { name => io::print("Hello, {name}"), _ => io::print("Hello, stranger") }}fn some(val: $T) $T?
Section titled “fn some(val: $T) $T?”Create a Maybe value containing the given value.
use ard/maybe
let value = maybe::some(42)fn none() $T?
Section titled “fn none() $T?”Create an empty Maybe value. Type parameters must be explicitly provided.
use ard/maybe
let empty: Int? = maybe::none()Maybe Type Methods
Section titled “Maybe Type Methods”All Maybe types have the following methods:
fn is_some() Bool
Section titled “fn is_some() Bool”Check if the Maybe contains a value.
use ard/maybe
let val: Int? = maybe::some(42)if val.is_some() { // has a value}fn is_none() Bool
Section titled “fn is_none() Bool”Check if the Maybe is empty.
use ard/maybe
let val: Int? = maybe::none()if val.is_none() { // is empty}fn or(default: $T) $T
Section titled “fn or(default: $T) $T”Get the value from the Maybe, or return a default if it’s empty.
use ard/maybe
let val: Int? = maybe::none()let result = val.or(0) // 0fn expect(message: Str) $T
Section titled “fn expect(message: Str) $T”Get the value from the Maybe, or panic with a message if it’s empty.
use ard/maybe
let val: Int? = maybe::some(42)let result = val.expect("expected a value") // 42fn map(with: fn($T) $U) $U?
Section titled “fn map(with: fn($T) $U) $U?”Transform a some value with a function that returns a plain value. The result is automatically wrapped in some(...). If the Maybe is none, the callback is not called and none passes through unchanged.
Use map when the transformation always produces a value.
use ard/maybe
let num: Int? = maybe::some(21)let doubled = num.map(fn(v) { v * 2 })let value = doubled.or(0) // 42
// none passes through untouchedlet empty: Int? = maybe::none()empty.map(fn(v) { v * 2 }).is_none() // trueYou can also provide explicit type arguments when you want to guide inference:
let as_text = num.map<Str>(fn(v) { "{v}" })fn and_then(with: fn($T) $U?) $U?
Section titled “fn and_then(with: fn($T) $U?) $U?”Chain operations that return a Maybe themselves (also known as flat_map in other languages). Unlike map, the callback is responsible for wrapping its return value in some(...) or returning none(). This lets the callback itself decide whether a value is present.
Use and_then when the next step might not produce a value.
use ard/maybe
fn even_only(num: Int) Int? { match num % 2 == 0 { true => maybe::some(num), false => maybe::none(), }}
let result = maybe::some(20).and_then(even_only)result.is_some() // true
// The callback can return none, unlike map:let odd = maybe::some(21).and_then(even_only)odd.is_none() // truePattern Matching with Maybe
Section titled “Pattern Matching with Maybe”Use match expressions to safely handle optional values:
use ard/maybeuse ard/io
fn main() { let maybe_age: Int? = maybe::some(30)
match maybe_age { age => io::print("Age: {age.to_str()}"), _ => io::print("Age unknown") }}When a Maybe value is matched:
- The first pattern captures the inner value if present
- The
_pattern matches when the value is absent (none)
Examples
Section titled “Examples”Check for Presence
Section titled “Check for Presence”use ard/maybeuse ard/io
fn main() { let email: Str? = maybe::none()
if email.is_some() { io::print("Email: {email.or("")}") } else { io::print("No email provided") }}Provide Defaults
Section titled “Provide Defaults”use ard/maybe
fn main() { let theme: Str? = maybe::none() let selected_theme = theme.or("light") // selected_theme is "light"}Process Optional Data
Section titled “Process Optional Data”Nullable struct fields accept unwrapped values directly — they are automatically wrapped in maybe::some():
struct User { name: Str, bio: Str?}
fn main() { // bio is automatically wrapped in maybe::some() let user = User { name: "Alice", bio: "Software engineer" }
match user.bio { description => { // has bio }, _ => { // no bio } }}Chain Operations with Maybe
Section titled “Chain Operations with Maybe”use ard/maybeuse ard/io
fn get_user_name(user_id: Int) Str? { if user_id == 1 { maybe::some("Alice") } else { maybe::none() }}
fn main() { let name = get_user_name(1) io::print(name.or("Unknown user"))}Work with Lists of Optional Values
Section titled “Work with Lists of Optional Values”use ard/maybeuse ard/list
fn main() { let values: [Int?] = [ maybe::some(1), maybe::none(), maybe::some(3) ]
// Using list operations with optional values}