Silex v0.47.1 / Docs Canonical source ↗

Represent an absent value

Add ? to a value type to represent either null or a value of that type.

struct Position {
    var x:int
}

func main() {
    let count:int?
    let title:str? = "Silex"
    var position:Position? = null

    print(count == null)
    print(title!)
    print(position == null)
}

A T value is automatically promoted to T?, but extraction is never implicit. The null literal requires an expected optional type.

Compose suffixes

Type suffixes compose from left to right. Position?[] is a list of optional positions; Position[]? is a list that is itself optional. int?[3] is a fixed array of three optional integers.

Optional suffixes may repeat. T?? means (T?)?: null initializes an absent outer layer, promoting a T? adds a present outer layer, and promoting a T makes every layer present. A conditional binding and the ! suffix remove one layer at a time; value!! is therefore explicit when two layers must be forced.

Prove the presence of a local variable

if position != null {
    print(position.x)
}

if position == null {
    print("absent")
} else {
    print(position.x)
}

The proof belongs to that variable and branch. Reassigning a var invalidates the proof for subsequent statements.

Bind the present value directly

if position = find_position() {
    print(position.x)
}

while var item = next_item() {
    item.advance()
}

Without a modifier, the local binding is immutable; explicit let has the same behavior, and var creates a mutable local copy. The source is evaluated once on every attempt.

Access without forcing presence

let x:int? = profile?.position?.x
position?.translate(3)

Every optional step requires its own ?.. Arguments to a safe method are evaluated only when the receiver is present. A safe call that modifies the value requires an optional var location.

An assignment can also traverse an optional path:

profile?.position?.x = 10
statistics?.accepted += 1
state?.values[index] = value

The root must be var. Silex evaluates the path from left to right and stops without effect at the first absent receiver. Indices and the right-hand value are evaluated only after every preceding segment is present. Simple assignment, compound assignment, ++, and -- share this short circuit. The statement produces no value.

Force a present value

let configuration = load_configuration()!
print(configuration.name)

The ! suffix evaluates its operand once and removes exactly one optional layer. Absence stops execution with the localized error forced optional extraction failed. The !value prefix remains Boolean negation; value! is the optional assertion.

Choose a replacement value

let display_name = declaration.alias ?? declaration.name
let port = configured_port() ?? default_port()

?? evaluates its optional left operand once. A present value is returned without evaluating the right side; absence evaluates the replacement. A T replacement produces a T, while T? ?? T? remains optional. The operator is right-associative and has lower precedence than logical and arithmetic operators.

Back to data types · Choose with an enum and match