Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boolean expression order of evaluation in Delphi?

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?

like image 457
Bruice Avatar asked Dec 06 '22 08:12

Bruice


1 Answers

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:

  • call B, compare to ''
  • call A, and it with the result of the string comparison
  • call C, 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.

like image 159
Stefan Glienke Avatar answered Dec 11 '22 10:12

Stefan Glienke