A quick post on a small but hugely useful little language feature in Oxygene… if expressions.
Many people will be familiar with the so-called ternary operator. Delphi developers will also be aware that there is no direct equivalent in Delphi.
In ‘C’ and other languages we can write a statement such as this:
x = a ? b : c;
The result is that x is assigned the value of b when a is true, otherwise x is assigned the value of c.
The ternary operator evaluates only either b or c as determined by the condition a.
In Delphi you can use the IfThen() function (for supported types of values of b and c) but this is notorious for the short-coming that regardless of the value of condition a both b and c will be evaluated.
At best this makes IfThen() potentially less efficient and at worst it can render it entirely useless if the evaluation of b or c has undesirable consequences or side-effects.
For example if you tried to use IfThen() to avoid a division by zero:
x := IfThen( divisor <> 0, numerator div divisor, 0);
This code will still throw a division by zero exception when divisor = zero. The equivalent ternary expression would not:
x = divisor != 0 ? numerator / divisor : 0;
In Delphi therefore you have no choice in these situations but to long-hand an if-else statement:
if divisor <> 0 then x := numerator div divisor else x := 0;
In Delphi therefore it is not uncommon to find this one, simple problem solved by at least three different techniques:
// 1. Where the values of b and c are supported by IfThen // and have no side effects: x := IfThen( a, b, c ); // 2. Where b and/or c are variable expressions that // do or may have side-effects: if a then x := b else x := c; // 3. Where the values of b and c are constant expressions: const AVALUE: array[false..true] of Integer = (0, 42); x := AVALUE[a];
Oxygene addresses this gap by simply re-purposing the if statement as an expression:
x := if divisor <> 0 then numerator div divisor else 0;
But Oxygene also goes further, extending the same behaviour to case statements, for example:
x := case selector of CONST_A : valueA; CONST_B : valueB; CONST_C : valueC; end;
Applying case and if in this way eliminates the duplication of the assignment expression in the overall statement and can be applied consistently in other scenarios such as choosing values to pass as parameters to functions:
Foo( a, if a > 42 then b else c );
The result is code that is consistent as well as both (imho) more concise and also clearer in intent than an if-else or (for case) a series of if-else if-else if statements.
Although a seemingly very small thing it is one of my favorite features of the Oxygene implementation of Object Pascal.