Type Annotations and Optionals
Zolo infers the type of every binding from its initializer — use the let x: T = …
annotation only when inference needs help (empty collections, ambiguous literals)
or when explicit types aid readability:
Inference vs annotation; typed arrays and maps such as [int] and map.
04-type-annotations.zolo
// Feature: Explicit type annotation on bindings
// Syntax: `let name: Type = value`
// When to use: when inference is not enough (generics, ambiguous
// literals, optional nil types), or to keep the intent documented
// in the signature.
// Inference: the type comes from the RHS.
let inferred = 42 // int
let pi_inf = 3.14 // float
print(inferred)
print(pi_inf)
// Explicit annotation.
let count: int = 100
let ratio: float = 0.618
let label: str = "production"
let active: bool = true
print(count)
print(ratio)
print(label)
print(active)
// Optional type — `T?` allows `nil`.
let maybe_name: str? = nil
let maybe_age: int? = 30
print(maybe_name ?? "anonymous")
print(maybe_age ?? 0)
// Annotation on arrays and maps.
let scores: [int] = [10, 20, 30]
let prices: map = #{apple: 1.50, bread: 3.20}
print(scores)
print(prices)
// Useful when the RHS is generic/ambiguous (e.g. empty array).
let empty: [int] = []
print(empty)
When a value can legitimately not exist, declare the type as T?. Zolo
allows nil only in optional types — the compiler rejects nil in bindings
without ?. The ?? operator provides a default when the value is nil:
T? allows nil; ?? returns the right-hand side when the value is nil; if let extracts the present value.
10-nullable-init.zolo
// Feature: Bindings with optional type `T?` and nil initialization
// Syntax: `let x: Type? = nil`
// When to use: when the value can legitimately be absent — search
// result, optional field, parse that may fail. In Zolo, `nil` is
// only allowed in types marked `T?`.
// Optional initialized as nil — filled in later.
var current_user: str? = nil
print(current_user ?? "anonymous") // anonymous
current_user = "Alice"
print(current_user ?? "anonymous") // Alice
// Result of a function that may fail.
fn find_user(id: int) -> str? {
if id == 1 { return "Alice" }
if id == 2 { return "Bob" }
return nil
}
let u1 = find_user(1)
let u3 = find_user(3)
print(u1 ?? "not found") // Alice
print(u3 ?? "not found") // not found
// Combining nullable + destructure (via `if let`).
if let name = find_user(2) {
print("found {name}") // found Bob
} else {
print("missing")
}
// Default sentinel via `??`.
let port: int? = nil
let actual_port = port ?? 8080
print(actual_port) // 8080
Challenge
Change let maybe_name: str? = nil to let maybe_name: str = nil and see the
type error the compiler emits.