Nullable Expressions
All Elements languages allow the use of Nullable Types in standard Arithmetic and Logical Expressions and will automatically propagate nullability to their result type. So if one element of an expression is nullable, that information will bubble up through the expression tree and the result will be nullable, too.
When using the Swift language, nullables need to be of the implicitly wrapped type (i.e.declared with !) to be used directly, or they can be unwrapped inline with ?.
Consider the following example:
var x: Int32 := 5;
var y: nullable Int32 := 10;
var z: nullable Int32;
var a := x + y + z;
Int32 x = 5;
Int32? y = 10;
Int32? z;
var a = x + y + z;
let x: Int32 = 5
let y: Int32! = 10
let z: Int32?
let a = x + y + z?;
Int32 x = 5;
Int32? y = 10;
Int32? z;
var a = x + y + z;
Dim x As Int32 = 5
Dum y As Int32? = 10
Dum z As Int32?
Dim a = x + y * z;
Both y and z are of nullable type. That means that the subexpression x + y will be promoted to be an nullable Int32 as well, it's value will be 15. Next, this value is then added to z, which is not only potentially nullable but in fact nil. Regardless of z’s value, the end result will be a nullable type again, and because z is nil, the end result, 15 + nil, is nil.
So this code declares a as a nullable Int32 (solely based on the input types of the expression) and at runtime a will evaluate to nil (because one on ifs inlut vaklues was nil)
Determining the Type of a Nullable Expression
To determine the type of an expression, the following rules are applied:
- Initially, the nullability characteristic of the operands is ignored, determining the result base type in the usual way.
- If any one of the operands is nullable, the result type will be nullable as well.
Consider the following example:
var x: Int32 := 5;
var y: nullable Double := 5.0;
var a := x + y; // 10, a will be a nullable Single
In step one, the base types of x and y (Int32 and Double) are considered to determine that the resulting expression will also be of type Double. Then, because one of the parameters (z) is nullable, the entire result is promoted to a nullable Double.
Equality of Nullable Types
The above applies to all operators with only a single important exception: equality comparisons (= and ≠ / <> / !=) always result in a not-nullable Boolean to preserve the established logic of comparing reference-based values. (Other comparison operators, i.e. <, ≤ > and ≥, will produce a nullable boolean as result if one of the operands is nullable, according to the above rules.)
For Example:
var x: Int32 := 5;
var y: nullable Int32 := 5;
var z: nullable Int32;
var a := x = y; // true, a will be a regular Boolean
var b := x = z; // false, b will be a regular Boolean
Determining the Result of a Nullable Expression
When evaluating expressions at runtime, the result will be nil, if one or both of the operands is nil; otherwise the result is the determined just as it would be for non-nullable expressions by applying the operator(s) to the respective values. It is worth noting that a single nil in a complex or nested expression will "bubble up" and turn the entire expression nil.
Examples (assuming the right-hand operator is a nullable Int32 type):
var x: Int32 := 5;
var y: nullable Int32 := 10;
var z: nullable Int32;
var a := x + z; // = nil
var b := x + y; // = 15;
var b := (x + z) * y; // = nil;
Notes
- The above rules are specific to nullable types, but do not necessarily apply to custom class based types that implement their own operators. For example, the
+concatenation operator on Strings will preserve the original string when appending anilstring via+. if,whileanduntilstatements will accept nullable booleans, and treatnilasfalse.
Result Tables
The following tables provide a matrix for how nil and Boolean values
interact.
Equality
The following rules apply to the equality (= and ≠/<>/!=)
operators:
- nil = nil =>
true - nil = non-nil =>
false - non-nil = nil =>
false - non-nil = non-nil => compare value
Non-Equality
- nil ≠ nil =>
false - nil ≠ non-nil =>
true - non-nil ≠ nil =>
true - non-nil ≠ non-nil => actual values are compared
Booleans
Truth table for the not / ! boolean operator
- (not
true) =>false - (not
false) =>true - (not
nil) =>nil
Truth table for the and / && boolean operator
trueandtrue=>truetrueandfalse=>falsetrueandnil=>nilfalseandtrue=>false— via Boolean Short-Circuitfalseandfalse=>false— via Boolean Short-Circuitfalseandnil=>false— via Boolean Short-Circuitnilandtrue=>nilnilandfalse=>falsenilandnil=>nil
Truth table for the or / || boolean operator
trueortrue=>true— via Boolean Short-Circuittrueorfalse=>true— via [Boolean Short-Circuittrueornil=>true— via [Boolean Short-Circuitfalseortrue=>truefalseorfalse=>falsefalseornil=>nilnilortrue=>truenilorfalse=>nilnilornil=>nil
Truth table for the xor / ^ boolean operator
truexortrue=>falsetruexorfalse=>truetruexornil=>nilfalsexortrue=>truefalsexorfalse=>falsefalsexornil=>nilnilxortrue=>nil— via Boolean Short-Circuitnilxorfalse=>nil— via Boolean Short-Circuitnilxornil=>nil— via Boolean Short-Circuit
Note: There is no XOR operator in SQL, which is where the nullable truth tables are based on, however, "A xor B" can be expressed as "not (A and B) and (A or B)" and the above truth table derived from that.
Truth table for the Oxygene implies boolean operator
trueimpliestrue=>truetrueimpliesfalse=>falsetrueimpliesnil=>nilfalseimpliestrue=>true— via Boolean Short-Circuitfalseimpliesfalse=>true— via Boolean Short-Circuitfalseimpliesnil=>true— via Boolean Short-Circuitnilimpliestrue=>nilnilimpliesfalse=>nilnilimpliesnil=>nil
Boolean Short-Circuit
Boolean Short-Circuit evaluation is possible for the following operators if the left operand has a specific value:
-
and/&&:false=>false -
or/||:true=>true -
xor/^:nil=>nil
(Note that xor/^ does not ever short-circuit for non-nullable expressions.)