Null Reference Safety

A null reference is a reference with no referent. Null references in code can cause various potential risks. Tony Hoare, a Turing Award winner, calls null references a "billion-dollar mistake".

Null references are one of the most common sources of errors in programming languages. If the language or type system does not guarantee that references are not null, programs may access members of a reference type without ensuring that the reference type is not null, causing errors or exceptions.

Null reference safety aims to eliminate the risk of null references in code.

Cangjie provides null reference safety. In Cangjie, no null value is provided. In other words, the reference types of Cangjie are always non-null. In this way, null references are prevented.

However, the representation of a null value is very useful semantically. In Cangjie, any type T may have a corresponding optional type Option<T>. A variable of type Option<T> may have a null value (None) or correspond to an actual value v of type T (Some(v)).

The optional enum type (Option<T>) is a standard algebraic data type representing a value that may be present or absent.

enum Option<T> {
    Some(T) | None
}

var a: Option<Int> = Some(123)
a = None

Note that Option<T> and T are two different types, and values of the two types cannot be converted to each other. Given an expression e of type Option<T>, we can only obtain a value of type T by pattern matching on e and receiving a value v in the Some(v) case. Therefore, any meaningful processing of the expression e needs to be accompanied by pattern matching and a corresponding check for None, so that it is impossible to directly dereference the null value None, thereby avoiding null reference exceptions.

Based on the frequent use of optional types, Cangjie also provides rich syntactic sugar support for them. For example, we can replace Option<T> with ?T, use the optional chaining operator (?.) to simplify member access, and use the null merge operator (??) to merge valid values.

var a: ?Int = None
a?.toString() // None
a ?? 123 // 123
a = Some(321)
a?.toString() // Some("321")
a ?? 123 // 321