Skip to main content

Optional Chaining

The optional chaining operator ?. provides safe member access on nullable values. If the left-hand side is null, the entire expression short-circuits to null instead of causing a runtime error.

Basic Usage

struct User {
name: str,
}

fn main() {
let user: User? = User { name: "Ada" };
let name: str? = user?.name; // "Ada"

let nobody: User? = null;
let n: str? = nobody?.name; // null
}

The result of a ?. expression is always nullable (T?), even if the accessed field itself is non-nullable.

Chaining Multiple Levels

?. can be chained through multiple levels of nullable fields:

struct Z {
val: i32,
}

struct Y {
z: Z?,
}

struct X {
y: Y?,
}

fn main() {
let x: X? = X { y: Y { z: Z { val: 42 } } };
let v: i32? = x?.y?.z?.val; // 42

let x_null: X? = null;
let v2: i32? = x_null?.y?.z?.val; // null (short-circuits at x_null)
}

Each ?. step checks for null before proceeding. If any step in the chain is null, the rest is skipped and the entire expression evaluates to null.

Result Type

The ?. operator always produces a nullable type. Assigning the result to a non-nullable variable is a compile error:

struct User {
name: str,
}

fn main() {
let user = User { name: "Ada" };
let name: str = user?.name; // error: type mismatch in assignment
}

Use a nullable type for the result:

let name: str? = user?.name;  // OK

Mixing ?. and .

When chaining through a nullable value into non-nullable fields, each step after the first ?. must also use ?.:

struct B {
c: i32,
}

struct A {
b: B, // non-nullable
}

fn main() {
let a: A? = A { b: B { c: 1 } };

// Correct:
let v: i32? = a?.b?.c;

// Error — cannot use `.` after `?.`:
// let v: i32? = a?.b.c;
}

Once a chain enters nullable context via ?., all subsequent member accesses must use ?. to propagate the nullable state.

Null Checking

After optional chaining, use standard null comparisons to unwrap the result:

let v: i32? = x?.y?.z?.val;

if v != null {
// v is i32? here, but known non-null
_ = os.write("value is {v}\n");
} else {
_ = os.write("value is null\n");
}

See also