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 returns true, if both the expression on the left and the one on the right are true.
  • or returns true, if either one of the expression on the left or the right is true.
  • xor returns true, if only one of the expression on the left or the right is true, but not both.
  • not returns true, if the value it precedes is false, otherwise it returns true. In other words, it reverses or negates the boolean value.
  • implies returns false, only if the expression on the left is true, 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 returns 1 for very bit that is 1 in both the expression on the left and the one on the right.
  • or returns 1, for every bit that is 1 either one of the expression on the left or the right.
  • xor returns 1 for every bit that is 1 in only one of the expression on the left or the right, but not both.
  • not returns 1, for every bit that is 0, and 0 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.