Pointers and optionals
*T is a pointer, and it is never null. Absence lives in ?T:
struct Node { key i32 next ?*Node}
func find(head ?*Node, key i32) ?*Node { mut cur := head for { if n := cur { if n.key == key { return n } cur = n.next } else { return nil } }}
func main() int { mut c := Node{key: 3, next: nil} mut b := Node{key: 2, next: &c} mut a := Node{key: 1, next: &b}
hit := find(&a, 3) orelse return 1 return int(hit.key) + 39}?*Node still fits in one word — the null pointer is the marker, so the safety
costs nothing. Over a non-pointer type, ?T is a value and a flag beside it.
Two ways to get at the value, and no third:
if n := opt { ... }runs the block with the unwrapped value boundopt orelse fallbackproduces the value or the fallback
An error’s name and message are available too, which is what a log line or a test failure wants:
import "std/io"
error NotFound = "there is nothing there"
func risky() !u64 { return error.NotFound}
func main() !int { risky() catch |e| { try io.Printf("gave up: {} — {}\n", nameof(e), e.Message()) } return 0}orelse also takes a jump, which is the shape you will write most:
p := lookup(key) orelse return error.NotFoundTo ask only whether something is there, compare it against nil:
import "std/io"import "std/os"
func main() !int { if os.Env("HOME") != nil { try io.Print("HOME is set\n") } return 0}That is the only comparison an optional has. Two of them cannot be compared, because that would mean comparing the values inside, and an absent one has none.