Optionals
As mentioned in the type system overview, all primitive types, Structs, and Messages can be nullable. That is, they don’t necessarily hold any value aside from null
— a special value that represents the intentional absence of any other value.
Variables or fields of Structs and Messages that can hold null
are called “optionals”. They’re useful for reducing state size when the variable isn’t necessarily used.
You can make any variable or field optional by adding a question mark (?
) after its type declaration. The only exceptions are map<K, V>
and bounced<Msg>
, in which you cannot make the inner key/value type (in the case of a map) or the inner Message (in the case of a bounced) optional.
Optional variables or optional fields that are not defined hold the null
value by default. You cannot access them without checking for null
first. However, if you’re certain they are not null
at a given moment, use the non-null assertion operator !!
to access their value.
Attempts to access the value of an optional variable or an optional field without using !!
or without checking for null
beforehand will result in a compilation error if the compiler can track it, or, if it cannot, in an exception with exit code 128: Null reference exception
.
Example of optionals:
struct StOpt { opt: Int?; // Int or null}
message MsOpt { opt: StOpt?; // Notice how the struct StOpt is used in this definition}
contract Optionals { opt: Int?; address: Address?;
init(opt: Int?) { // optionals as parameters self.opt = opt; self.address = null; // explicit null value }
receive(msg: MsOpt) { let opt: Int? = 12; // defining a new variable if (self.opt != null) { // explicit check self.opt = opt!!; // using !! as we know that opt value isn't null } }}