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 anil
string via+
. if
,while
anduntil
statements will accept nullable booleans, and treatnil
asfalse
.
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
true
andtrue
=>true
true
andfalse
=>false
true
andnil
=>nil
false
andtrue
=>false
— via Boolean Short-Circuitfalse
andfalse
=>false
— via Boolean Short-Circuitfalse
andnil
=>false
— via Boolean Short-Circuitnil
andtrue
=>nil
nil
andfalse
=>false
nil
andnil
=>nil
Truth table for the or
/ ||
boolean operator
true
ortrue
=>true
— via Boolean Short-Circuittrue
orfalse
=>true
— via [Boolean Short-Circuittrue
ornil
=>true
— via [Boolean Short-Circuitfalse
ortrue
=>true
false
orfalse
=>false
false
ornil
=>nil
nil
ortrue
=>true
nil
orfalse
=>nil
nil
ornil
=>nil
Truth table for the xor
/ ^
boolean operator
true
xortrue
=>false
true
xorfalse
=>true
true
xornil
=>nil
false
xortrue
=>true
false
xorfalse
=>false
false
xornil
=>nil
nil
xortrue
=>nil
— via Boolean Short-Circuitnil
xorfalse
=>nil
— via Boolean Short-Circuitnil
xornil
=>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
true
impliestrue
=>true
true
impliesfalse
=>false
true
impliesnil
=>nil
false
impliestrue
=>true
— via Boolean Short-Circuitfalse
impliesfalse
=>true
— via Boolean Short-Circuitfalse
impliesnil
=>true
— via Boolean Short-Circuitnil
impliestrue
=>nil
nil
impliesfalse
=>nil
nil
impliesnil
=>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.)