Arithmetic & Logical Expressions
Oxygene allows the use of operators to create comparisons, arithmetic expressions and logic expressions. The language has well-defined set of operators for these scenarios, but Types can provide custom implementations for operators, using a technique called Custom Operators, a.k.a. Operator Overloading.
Comparisons
Supported Operators: =
, ≠
, <
, ≤
, >
, ≥
(and <=
, >=
, <>
)
The above operators can be used to compare two operands for equality, non-equality and sort order.
For types that to not provide a custom equality and/or non-equality operator implementation, =
and ≠
will compare the object reference (i.e. identity) of heap based types (such as Classes), and do a memory/value compare for stack-based types (such as Integers, Booleans, Floats, and Records).
If a matching custom =
or ≠
operator is defined on the type of either the left or the right-hand expression, it will be called instead.
The <
, ≤
, >
, ≥
operators are only supported if the appropriate custom operator is implemented on one of the types.
var x := 5;
var y := 10;
if x ≤ 5 then ...
Note : Oxygene supports rich unicode ≤
, ≥
and ≠
operators, but also, for backwards compatibility, the double-character <=
, >=
and <>
spelling. Fire and Water will auto-correct <=
, >=
and !=
to ≤
, ≥
and ≠
, respectively, and on macOS you can use ⌥<, ⌥> and ⌥= to type these operators directly, as well.
Double Boolean Comparisons
Oxygene provides a convenient short-hand for comparing a value against two boundaries at once, via Double Boolean Comparisons. a double boolean comparisons is true only of both the first and the second hald of the expression is true. It is convenient for testing if a value falls within a range between two values:
var y := 10;
if 10 ≤ x ≤ 15 then
writeLn("x is between 10 and 15").
The above check essentially expands to
if (10 ≤ x) and (x ≤ 15) then.
...
Arithmetic Operators
Supported Operators: +
, -
, *
, /
, **
, div
, mod
The above operators are used to carry out mathematical operations on two operands
+
evaluates to the sum of two values by adding them.-
evaluates to the difference of two values by subtracting them.*
evaluates to the product of two values by multiplying them./
evaluates to the fraction of two values by dividing them.-
**
evaluates to the power of two values. -
div
also evaluates to the fraction of two values by dividing them. It is provided for Compatibility with Delphi (see below). mod
evaluates to the remainder of two values left over when performing an integer division.
var a := 2+2; // 4
var b := 12+3; // 9
var c := 3*9; // 27
var d := 8/2; // 4
var d := 2**10; // 1024
var d := 10.0/4.0; // 2.5
var d := 10.0 div 4.0; // 2.5
var d := 10.0 mod 4.0; // 2
Note that all operators use the type of the input values as result type. For example Dividing two integers will always perform an integer division, producing an integer, potentially losing the remainder. If one of the two operands is a floating point type, the result will be a float, as well.
Also note that Oxygene will apply operator precedence (more on that below for combined expressions, according to mathematical rules (*
an /
tage precedence before +
and -
, etc).
var a := 5 + 10 * 2; // 25
var b := 5 + (10 * 2); // 25
var b := (5 + 10) * 2); // 30
Note on Delphi Compatibility Mode: The /
and div
operators will behave differently in Delphi Compatibility Mode. As in Delphi, the operators will not infer the result from the operands. Instead , /
will always result in a floating point, while div
will always perform an rounded integer division.
Logical Operators
Supported Operators: and
, or
, xor
, not
and implies
The above operators can be used to combine boolean expressions. and
, or
and xor
are binary operators, which means the take two parameters; not
is a unary prefix operator and takes one parameter to it's right.
and
returnstrue
, if both the expression on the left and the one on the right are true.or
returnstrue
, if either one of the expression on the left or the right is true.xor
returnstrue
, if only one of the expression on the left or the right is true, but not both.not
returnstrue
, if the value it precedes isfalse
, otherwise it returnstrue
. In other words, it reverses or negates the boolean value.implies
returnsfalse
, only if the expression on the left istrue
, but the the expression on the right is not.
var a := x and y;
var b := x or y;
var c := x xor y;
var d := not x;
var e := x implies y;
By default, Oxygene will apply Boolean Short-Circuit, where starting from the left, the compiler will stop evaluating expressions once the outcome of the expression is determined.
For example, if the left-hand side of an and
operation is false
, the result will always be false
. Likewise, if the left-hand side of an or
operation is true
, the result will always be true
. In both cases, evaluation of the right will not be evaluated at all.
Note that different than in many other, especially C-based languages, the logical and
, or
and xor
operators take precedence over comparisons. For this reason, combining multiple comparisons with logical operators will often require parenthesis:
if x > 5 and y < 10 then ... // 🛑 compiler error, because "(5 and y)" would be evaluated first
if (x > 5) and (y < 10) then ... // ✅ works!
Bitwise Operators
Supported Operators: and
, or
, xor
and not
The save four operators can also be used for bitwise operations on numeric (integer) values. When doing so, they apply above boolean logic on each bit of the numeric value's in-memory representation, with 0 and 1 represening false
or true
, respectively.
and
returns1
for very bit that is1
in both the expression on the left and the one on the right.or
returns1
, for every bit that is1
either one of the expression on the left or the right.xor
returns1
for every bit that is1
in only one of the expression on the left or the right, but not both.not
returns1
, for every bit that is0
, and0
for every bit that is one. In other words, it inverts the bit mask of the value.
var a := %0000 1100 and $0000 1010; // %0000 1000
var b := %0000 1100 or $0000 1010; // %0000 1110
var c := %0000 1100 and $0000 1010; // %1111 0110
var d := not %0000 1100 // %1111 0011
Operator Precendence
...
Nesting Expressions with Parenthesis
Parenthesis allow you to visually enclose sub-expressions in order to indicate the order of precedence in which they will be executed within a larger expression. This is especially helpful when using the arithmetic and logical expressions discussed in this topic, but can also help clarify other more complex expressions.
var x := 3 + 2 * 5 // evaluates to 3 + 10 = 13, as * has precedence over + by default.
var x := (3 + 2) * 5 // evaluates to 5 * 5 = 25, as the parenthesis cause the addition to be performed first.
Nullable Types in Expressions
Please refer to the Nullable Types In Expressions topic for some caveats when using expressions that contain potential nil values
. In particular, a nil
value anywhere in an operator expression propagates outwards, potentially turning the entire expression nil
. This can have some unintuitive results when working wit booleans, in particular in combination with the not
operator, where not nil
remains nil
. Also consider Boolean Short-Circuit.