Operators
Operators are special symbols that perform a computation for one or more values. They are either unary, binary, or ternary.
-
Unary operators perform an operation for a single value. The unary operator symbol appears before the value.
-
Binary operators operate on two values. The binary operator symbol appears between the two values (infix).
-
Ternary operators operate on three values. The first operator symbol appears between the first and second value, the second operator symbol appears between the second and third value (infix).
Assignment Operator (=
)
The binary assignment operator =
can be used
to assign a new value to a variable.
It is only allowed in a statement and is not allowed in expressions.
Assignments to constants are invalid.
The left-hand side of the assignment operand must be an identifier. For arrays and dictionaries, this identifier can be followed by one or more index or access expressions.
Force-assignment operator (<-!
)
The force-assignment operator (<-!
) assigns a resource-typed value
to an optional-typed variable if the variable is nil.
If the variable being assigned to is non-nil,
the execution of the program aborts.
The force-assignment operator is only used for resource types.
Swapping Operator (<->
)
The binary swap operator <->
can be used
to exchange the values of two variables.
It is only allowed in a statement and is not allowed in expressions.
Both sides of the swap operation must be variable, assignment to constants is invalid.
Both sides of the swap operation must be an identifier, followed by one or more index or access expressions.
Arithmetic Operators
The unary pefix operator -
negates an integer:
There are four binary arithmetic operators:
- Addition:
+
- Subtraction:
-
- Multiplication:
*
- Division:
/
- Remainder:
%
The arguments for the operators need to be of the same type. The result is always the same type as the arguments.
The division and remainder operators abort the program when the divisor is zero.
Arithmetic operations on the signed integer types
Int8
, Int16
, Int32
, Int64
, Int128
, Int256
,
and on the unsigned integer types
UInt8
, UInt16
, UInt32
, UInt64
, UInt128
, UInt256
,
do not cause values to overflow or underflow.
Arithmetic operations on the unsigned integer types
Word8
, Word16
, Word32
, Word64
may cause values to overflow or underflow.
For example, the maximum value of an unsigned 8-bit integer is 255 (binary 11111111). Adding 1 results in an overflow, truncation to 8 bits, and the value 0.
Similarly, for the minimum value 0, subtracting 1 wraps around and results in the maximum value 255.
Arithmetics on number super-types
Arithmetic operators are not supported for number supertypes
(Number
, SignedNumber
, FixedPoint
, SignedFixedPoint
, Integer
, SignedInteger
),
as they may or may not succeed at run-time.
Values of these types need to be cast to the desired type before performing the arithmetic operation.
Logical Operators
Logical operators work with the boolean values true
and false
.
-
Logical NOT:
!a
This unary prefix operator logically negates a boolean:
-
Logical AND:
a && b
If the left-hand side is false, the right-hand side is not evaluated.
-
Logical OR:
a || b
If the left-hand side is true, the right-hand side is not evaluated.
Comparison Operators
Comparison operators work with boolean and integer values.
-
Equality:
==
, is supported for booleans, numbers, addresses, strings, characters, enums, paths,Type
values, references, andVoid
values (()
). Variable-sized arrays, fixed-size arrays, dictionaries, and optionals also support equality tests if their inner types do.Both sides of the equality operator may be optional, even of different levels, so it is for example possible to compare a non-optional with a double-optional (
??
). -
Inequality:
!=
, is supported for booleans, numbers, addresses, strings, characters, enums, paths,Type
values, references, andVoid
values (()
). Variable-sized arrays, fixed-size arrays, dictionaries, and optionals also support inequality tests if their inner types do.Both sides of the inequality operator may be optional, even of different levels, so it is for example possible to compare a non-optional with a double-optional (
??
). -
Less than:
<
, for integers, booleans, characters and strings -
Less or equal than:
<=
, for integers, booleans, characters and strings -
Greater than:
>
, for integers, booleans, characters and strings -
Greater or equal than:
>=
, for integers, booleans, characters and strings
Comparing number super-types
Similar to arithmetic operators, comparison operators are also not supported for number supertypes
(Number
, SignedNumber
FixedPoint
, SignedFixedPoint
, Integer
, SignedInteger
),
as they may or may not succeed at run-time.
Values of these types need to be cast to the desired type before performing the arithmetic operation.
Bitwise Operators
Bitwise operators enable the manipulation of individual bits of unsigned and signed integers. They're often used in low-level programming.
-
Bitwise AND:
a & b
Returns a new integer whose bits are 1 only if the bits were 1 in both input integers:
-
Bitwise OR:
a | b
Returns a new integer whose bits are 1 only if the bits were 1 in either input integers:
-
Bitwise XOR:
a ^ b
Returns a new integer whose bits are 1 where the input bits are different, and are 0 where the input bits are the same:
Bitwise Shifting Operators
-
Bitwise LEFT SHIFT:
a << b
Returns a new integer with all bits moved to the left by a certain number of places.
-
Bitwise RIGHT SHIFT:
a >> b
Returns a new integer with all bits moved to the right by a certain number of places.
For unsigned integers, the bitwise shifting operators perform logical shifting,
for signed integers, they perform arithmetic shifting.
Also note that for a << b
or a >> b
, b
must fit into a 64-bit integer.
Ternary Conditional Operator
There is only one ternary conditional operator, the ternary conditional operator (a ? b : c
).
It behaves like an if-statement, but is an expression: If the first operator value is true, the second operator value is returned. If the first operator value is false, the third value is returned.
The first value must be a boolean (must have the type Bool
).
The second value and third value can be of any type.
The result type is the least common supertype of the second and third value.
Casting Operators
Static Casting Operator (as
)
The static casting operator as
can be used to statically type cast a value to a type.
If the static type of the value is a subtype of the given type (the "target" type), the operator returns the value as the given type.
The cast is performed statically, i.e. when the program is type-checked. Only the static type of the value is considered, not the run-time type of the value.
This means it is not possible to downcast using this operator.
Consider using the conditional downcasting operator as?
instead.
Conditional Downcasting Operator (as?
)
The conditional downcasting operator as?
can be used to dynamically type cast a value to a type.
The operator returns an optional.
If the value has a run-time type that is a subtype of the target type
the operator returns the value as the target type,
otherwise the result is nil
.
The cast is performed at run-time, i.e. when the program is executed, not statically, i.e. when the program is checked.
Downcasting works for concrete types, but also works e.g. for nested types (e.g. arrays), interfaces, optionals, etc.
Force-downcasting Operator (as!
)
The force-downcasting operator as!
behaves like the
conditional downcasting operator as?
.
However, if the cast succeeds, it returns a value of the given type instead of an optional,
and if the cast fails, it aborts the program instead of returning nil
,
Optional Operators
Nil-Coalescing Operator (??
)
The nil-coalescing operator ??
returns
the value inside an optional if it contains a value,
or returns an alternative value if the optional has no value,
i.e., the optional value is nil
.
If the left-hand side is non-nil, the right-hand side is not evaluated.
The nil-coalescing operator can only be applied to values which have an optional type.
The type of the right-hand side of the operator (the alternative value) must be a subtype of the type of left-hand side, i.e. the right-hand side of the operator must be the non-optional or optional type matching the type of the left-hand side.
Force Unwrap Operator (!
)
The force-unwrap operator (!
) returns
the value inside an optional if it contains a value,
or panics and aborts the execution if the optional has no value,
i.e., the optional value is nil
.
The force-unwrap operator can only be applied to values which have an optional type.
Precedence and Associativity
Operators have the following precedences, highest to lowest:
- Unary precedence:
-
,!
,<-
- Cast precedence:
as
,as?
,as!
- Multiplication precedence:
*
,/
,%
- Addition precedence:
+
,-
- Bitwise shift precedence:
<<
,>>
- Bitwise conjunction precedence:
&
- Bitwise exclusive disjunction precedence:
^
- Bitwise disjunction precedence:
|
- Nil-Coalescing precedence:
??
- Relational precedence:
<
,<=
,>
,>=
- Equality precedence:
==
,!=
- Logical conjunction precedence:
&&
- Logical disjunction precedence:
||
- Ternary precedence:
? :
All operators are left-associative, except for the following operators which are right-associative:
- Ternary operator
- Nil-coalescing operator
Expressions can be wrapped in parentheses to override precedence conventions,
i.e. an alternate order should be indicated, or when the default order should be emphasized
e.g. to avoid confusion.
For example, (2 + 3) * 4
forces addition to precede multiplication,
and 5 + (6 * 7)
reinforces the default order.