Accessing Fields and Functions of Composite Types Using Optional Chaining

If a composite type with fields and functions is wrapped in an optional, optional chaining can be used to get those values or call the function without having to get the value of the optional first.

Optional chaining is used by adding a ? before the . access operator for fields or functions of an optional composite type.

When getting a field value or calling a function with a return value, the access returns the value as an optional. If the object doesn't exist, the value will always be nil

When calling a function on an optional like this, if the object doesn't exist, nothing will happen and the execution will continue.

It is still invalid to access an undeclared field of an optional composite type.

// Declare a struct with a field and method.
pub struct Value {
    pub var number: Int

    init() {
        self.number = 2
    }

    pub fun set(new: Int) {
        self.number = new
    }

    pub fun setAndReturn(new: Int): Int {
        self.number = new
        return new
    }
}

// Create a new instance of the struct as an optional
let value: Value? = Value()
// Create another optional with the same type, but nil
let noValue: Value? = nil

// Access the `number` field using optional chaining
let twoOpt = value?.number
// Because `value` is an optional, `twoOpt` has type `Int?`
let two = zeroOpt ?? 0
// `two` is `2`

// Try to access the `number` field of `noValue`, which has type `Value?`
// This still returns an `Int?`
let nilValue = noValue?.number
// This time, since `noValue` is `nil`, `nilValue` will also be `nil`

// Call the `set` function of the struct
// whether or not the object exists, this will not fail
value?.set(new: 4)
noValue?.set(new: 4)

// Call the `setAndReturn` function, which returns an `Int`
// Because `value` is an optional, the return value is type `Int?`
let sixOpt = value?.setAndReturn(new: 6)
let six = sixOpt ?? 0
// `six` is `6`

This is also possible by using the force-unwrap operator (!).

Forced-Optional chaining is used by adding a ! before the . access operator for fields or functions of an optional composite type.

When getting a field value or calling a function with a return value, the access returns the value. If the object doesn't exist, the execution will panic and revert.

It is still invalid to access an undeclared field of an optional composite type.

// Declare a struct with a field and method.
pub struct Value {
    pub var number: Int

    init() {
        self.number = 2
    }

    pub fun set(new: Int) {
        self.number = new
    }

    pub fun setAndReturn(new: Int): Int {
        self.number = new
        return new
    }
}

// Create a new instance of the struct as an optional
let value: Value? = Value()
// Create another optional with the same type, but nil
let noValue: Value? = nil

// Access the `number` field using force-optional chaining
let two = value!.number
// `two` is `2`

// Try to access the `number` field of `noValue`, which has type `Value?`
// Run-time error: This time, since `noValue` is `nil`,
// the program execution will revert
let number = noValue!.number

// Call the `set` function of the struct

// This succeeds and sets the value to 4
value!.set(new: 4)

// Run-time error: Since `noValue` is nil, the value is not set
// and the program execution reverts.
noValue!.set(new: 4)

// Call the `setAndReturn` function, which returns an `Int`
// Because we use force-unwrap before calling the function,
// the return value is type `Int`
let six = value!.setAndReturn(new: 6)
// `six` is `6`

Last updated