Coalesce Expressions
There are two forms of this - nil-coalesce and nonNil-coalesce. In both cases they evaluate the first expression and if it is nil (nonNil) return the second expression otherwise return the first expression.
They are convenient shorthand for respectively testing an expression against nil and returning a default or testing against nonNil and returning something else (usually a deref of the first expression)
Nil Coalesce
The nil coalesce binary expression evaluates to the first non-nil value. There is an augmented assignment version of it as well.
Grammar
<a> ? <b>
The expression evaluates to a unless that value is nil, in which case, it evaluates to b.
Although uncommon, nothing prevents b itself from also being nil. Neither expression will be evaluated more than once and if a is non-nil then b will not be evaluated at all.
The type of the coalesce expression is the greatest common denominator between the type of a and the type of b.
Grammar
<a> ?= <b>
In the augmented assignment version, the result is assigned back to a. This requires that b is type compatible with a or a compilation error will occur.
Examples
# Example 1 print name ? 'NONAME' # Example 2 def foo(factor as decimal?) factor ?= 1 # 'normalize' factor before proceeding with the rest of implementation ... # Example 3 # this: name = if(employee.manager.name<>nil, employee.manager.name, 'NONAME') # can evaluate the key expression twice and is less succinct than: name = employee.manager.name ? 'NONAME'
NonNil Coalesce
The nonNil coalesce binary expression evaluates the second expression if the first is a non-nil value. If the first expression is nil it just returns it. There is an augmented assignment version of it as well.
Grammar
<a> ! <b>
The expression evaluates to a if that value is nil, otherwise it evaluates to b.
Although uncommon, nothing prevents b itself from also being nil. Neither expression will be evaluated more than once and if a is nil then b will not be evaluated at all.
The type of the coalesce expression is the greatest common denominator between the type 'nil' and the type of b. (Nilable Type of b)
Grammar
<a> != <b>
In the augmented assignment version, the result is assigned back to a. This requires that b is type compatible with a or a compilation error will occur.
Note: this looks like a boolean comparison (not equals) in other languages.
# Example 1 print x ! x.name # if x is not nil return its member name else nil # name or default regardless of x or x.name nil print x ! x.name ? 'NONAME' # Example 2 current = list current != current.head # (not a comparison) nil if list nil or list.head nil if current # process # Example 3 name = if(employee and employee.manager and employee.manager.name, employee.manager.name, 'NONAME') # is less succinct than: name = employee ! employee.manager ! employee.manager.name ? 'NONAME' # assumes derefs are idempotent (same returns on each call or deref) # Example 4 #if calls are NOT idempotent need to capture each deref and use it subsequently # assuming employee.manager returns nil or a different value on each visit as in some places mgrName = employee ! (m = employee.manager) ! m.name ? 'NONAME'