I would like to know if the following code may ever fail with the access violation or if it's safe. Is the first member of the statement with AND operator always checked as first or may be (by some compiler optimization or something) checked the second one as first ?
var
Item: TSomething;
procedure DoSomething;
begin
if Assigned(Item) and (Item.SomeProperty) then
DoSomethingElse;
end;
Is the code above definitely safe ?
Thanks!
The logical AND operator ( && ) returns true if both operands are true and returns false otherwise. The operands are implicitly converted to type bool before evaluation, and the result is of type bool .
Order of evaluation refers to the operator precedence and associativity rules according to which mathematical expressions are evaluated.
The Boolean AND and OR operators perform short-circuit evaluation, that is, they evaluate the expression on the right of the operator only when it is necessary to determine the overall result of the expression.
Short-Circuit Evaluation: Short-circuiting is a programming concept in which the compiler skips the execution or evaluation of some sub-expressions in a logical expression. The compiler stops evaluating the further sub-expressions as soon as the value of the expression is determined.
The code is safe given boolean short-circuit evaluation is active:
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.
It is a bit confusing as the B
(or BOOLEVAL
with long name) directive must be turned OFF to switch short-circuit evaluation ON...
See also Operator Precedence.
It depends on your Item.SomeProperty type. If it is Variant, or if there is a variant to be evaluated before it, it will be evaluated and cause AV.
Edit : Forget to mention the workaround : If the SomeProperty is Variant type, you can use
if Assigned(Item) and StrToBool(Item.SomeProperty) then
It do spend some time to convert the variable to String then back to boolean but at lease it can satisfy all cases of being true / false / non-existence.
Below is a test case for you to see :
unit Unit4;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Generics.Collections;
type
TTestObj = class
public
V : Variant;
I : Integer;
end;
TForm4 = class(TForm)
btn1: TButton;
btn2: TButton;
btn3: TButton;
procedure btn1Click(Sender: TObject);
procedure btn2Click(Sender: TObject);
procedure btn3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
TOV : TTestObj;
end;
var
Form4: TForm4;
implementation
{$R *.dfm}
procedure TForm4.btn1Click(Sender: TObject);
begin
if Assigned(TOV) and (TOV.I = 10) then
ShowMessage('You will never see this though no AV!');
end;
procedure TForm4.btn2Click(Sender: TObject);
begin
if Assigned(TOV) and StrToBool(TOV.V) then
ShowMessage('You will not see AV with StrToBool!');
if Assigned(TOV) and TOV.V then
ShowMessage('You will never see this but AVed!');
end;
procedure TForm4.btn3Click(Sender: TObject);
var
V : Variant;
begin
V := False;
if Assigned(TOV) and V and (TOV.I = 10) then
ShowMessage('You will see AV!');
end;
end.
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