if exp1 and exp2 and exp3 then
//something
In Delphi is the order of evaluation exp1, exp2 and exp3 (of course they are all Boolean
) is defined or random?
if exp1 and exp2 and exp3 then
//something
In Delphi is the order of evaluation exp1, exp2 and exp3 (of course they are all Boolean
) is defined or random?
The order of evaluation is only defined when Boolean Short-Circuit Evaluation is enabled. Then, as the documentation in Complete Versus Short-Circuit Boolean Evaluation explains, evaluation is left to right.
If Boolean Short-Circuit Evaluation is not enabled, the order is undefined. The following code demonstrates this:
{$APPTYPE CONSOLE}
function A: boolean;
begin
Result := True;
Write('A ');
end;
function B: string;
begin
Result := '';
Write('B ');
end;
function C: Integer;
begin
Result := 0;
Write('C ');
end;
begin
{$O+}
Writeln('short circuit on');
{$B-}
if A and (B = '') and (C = 0) then Writeln;
Writeln('short circuit off');
{$B+}
if A and (B = '') and (C = 0) then Writeln;
end.
For the first one, you get printed A B C
, and for the second one you get B A C
.
And that was compiled for Win32 - to make this spicy, and bring home the point of this being Undefined, lets run it on Win64 where we get A B C
in both cases.
You might say: "Ok, but maybe just B was called first but the evaluation of the boolean expression B = ''
is evaluated in the correct order." Let's take a look at the assembler code that gets executed:
if A and (B = '') and (C = 0) then Writeln;
0040B17C 8D45E8 lea eax,[ebp-$18]
0040B17F E864EAFFFF call B
0040B184 837DE800 cmp dword ptr [ebp-$18],$00
0040B188 0F94C3 setz bl
0040B18B E81CEAFFFF call A
0040B190 22D8 and bl,al
0040B192 E891EAFFFF call C
0040B197 85C0 test eax,eax
0040B199 0F94C0 setz al
0040B19C 22D8 and bl,al
Nope:
B
, compare to ''
A
, and
it with the result of the string comparisonC
, compare with 0
, and
it with the result of the previous and
Which translates to (written in left to right order):
((B = '') and A) and (C = 0)
Addendum: Because I saw this mentioned in another answer and discussed in the comments. Parentheses are no solution to force order of evaluation of operands. You can only group operations but the compiler might still decide to evaluate the right operand first.
In the code above there is no way to put any parentheses to get A B C
simply because the compiler flipped the first two operands. It then however executed the operators from left to right and that is something to easily confuse - the question was not whether the first or the second and
was executed first but the order of the boolean expressions - the operands.
The documentation will guide you of course.
I have found that in more complex if statements the compiler does not do what even experienced programmers expected when they wrote the code, often because they are including logical nots and mixing boolean ands and ors. Remembering the precedence and association rules is not always easy.
My tip is to be explicit about what you want and put brackets around the terms. The compiler won't mind and it makes it clear what you intended when you or someone else reviews the code.
With compound if statements laying out the logical parts together can aso help humans to understand what was meant.
For example:
if( ((pObjectRef<>nil) And (pObjecRef.Property=SomeValue)) Or
((pAlternateObject<>nil) And
((pAlternatObject.Property=AnotherValue) Or
(pAlternatObject.Property=YetAnotherValue))) ) then
begin
...
end