I've had to pick up Delphi for a recent contract piece of work I am doing and one of the things I'd like someone to clarify is the execution of logic in a conditional statement such as an if
.
I come from a background in C/C++ and in those languages, as soon as an if
statement is known to fail, the rest of the logic is not executed. For example:
if (somefunc() == FALSE && anotherfunc() == TRUE)
In the case above, if somefunc()
returns TRUE
then anotherfunc()
is never called.
In Delphi from what I can see so far, this does not hold true. Rather, for
if (somefunc() = False and anotherfunc() = True) then
then, irrespective of what somefunc()
returns, anotherfunc()
will be called.
I've read various Delphi books, and reread some of the conditional chapters and can't find mention of this behaviour anywhere at all. Can anyone point me to somewhere in Delphi or Pascal where this behaviour is stated?
The documentation link is here:
Boolean short-circuit evaluation
Type Switch Syntax {$B+} or {$B-} {$BOOLEVAL ON} or {$BOOLEVAL OFF} Default {$B-} {$BOOLEVAL OFF} Scope Local The $B directive switches between the two different models of Delphi code generation for the and and or Boolean operators.
In the {$B+} state, the compiler generates code for complete Boolean expression evaluation. This means that every operand of a Boolean expression built from the and and or operators is guaranteed to be evaluated, even when the result of the entire expression is already known.
In the {$B-} state, the compiler generates code for short-circuit Boolean expression evaluation, which means that evaluation stops as soon as the result of the entire expression becomes evident in left to right order of evaluation.
As you can see, the default option is for short-circuit evaluation.
Unfortunately you got a little mixed up in your test. Your Delphi code is in fact quite different from the C code.
if (somefunc() == FALSE && anotherfunc() == TRUE) // C code
if (somefunc() = False and anotherfunc() = True) then // Delphi code
In Delphi the and
operator has a higher precedence than the equality operator =
. Which means that your Delphi code is equivalent to:
if (somefunc() = (True and anotherfunc()) = True) then
But in C and C++, the precedence is the other way around. So &&
has lower precedence than ==
. And so the Delphi and C++ if statements in your question are logically different, irrespective of short-circuit evaluation.
I'm quite sure that you really meant to write your Delphi code like this:
if ((somefunc() = False) and (anotherfunc() = True)) then
That would give the same logic as your C++ code, and you would have seen the same behaviour due to short circuit evaluation.
Finally, you should never test against False
and True
in Delphi. Always write the code like this:
if not somefunc() and anotherfunc() then
If your function anotherfunc()
gets called on this code
if (somefunc() = False and anotherfunc() = True) then
then you have set the BOOLEVAL ON
As David pointed out the compiler first evaluate False and anotherfunc()
In BOOLEVAL OFF
mode the compiler knows, that False and AnyBoolState
will result in False
and therefore anotherfunc()
is not called (in fact it will never be called).
As a simple test on that I extended the jachaguate program to show your expression
program AndEvaluation;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils;
function FalseFunc( const AName : string ) : Boolean;
begin
Write( AName, '(False)', '-' );
Result := False;
end;
function TrueFunc( const AName : string ) : Boolean;
begin
Write( AName, '(True)', '-' );
Result := True;
end;
begin
try
// (somefunc() = False and anotherfunc() = True)
//
// in this testcase translated to:
//
// somefunc() => FalseFunc( 'First' )
// False => FalseFunc( 'Second' )
// anotherfunc() => TrueFunc( 'Third' )
// True => TrueFunc( 'Fourth' )
{$B+}
Writeln( 'BOOLEVAL ON' );
if ( FalseFunc( 'First' ) = FalseFunc( 'Second' ) and TrueFunc( 'Third' ) = TrueFunc( 'Fourth' ) )
then
Writeln( 'True' )
else
Writeln( 'False' );
{$B-}
Writeln( 'BOOLEVAL OFF' );
if ( FalseFunc( 'First' ) = FalseFunc( 'Second' ) and TrueFunc( 'Third' ) = TrueFunc( 'Fourth' ) )
then
Writeln( 'True' )
else
Writeln( 'False' );
except
on E : Exception do
Writeln( E.ClassName, ': ', E.Message );
end;
ReadLn;
end.
And now lets have a look at the result
BOOLEVAL ON
Second(False)-Third(True)-First(False)-Fourth(True)-True
BOOLEVAL OFF
First(False)-Second(False)-Fourth(True)-True
As the output explains having BOOLEVAL ON
your anotherfunc()
will be called before somefunc()
is called.
With BOOLEVAL OFF
your anotherfunc()
is never called.
If you want to have the same as
if (somefunc() == FALSE && anotherfunc() == FALSE)
you have to translate it like this
if ( somefunc() = False ) and ( anotherfunc() = False ) then
or the better and shorter way
if not somefunc() and not anotherfunc() then
or maybe even shorter
if not( somefunc() or anotherfunc() ) then
But to avoid getting anotherfunc()
called every time you have to set BOOLEVAL OFF
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With