This is embarrasing, I forgot variant expressions "and" and "or" do not short-circuit boolean evaluation

Comments

  1. Sorry, I don't quite understand...?

    ReplyDelete
  2. If either operand involves a Variant, the compiler always performs complete evaluation (even in the {$B} state).
    from first Embarcadero result in Google search:
    http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/devcommon/expressions_xml.html

    ReplyDelete
  3. function A:Variant... end function B:Variant... end ... A and B ... Both functions will always be called, versus just calling A when it returns True

    ReplyDelete
  4. Because the and with variants is not like a regular and with boolean expressions but rather a function that takes two Variants and returns a boolean (see System.Variants._VarAnd). And then it is clear why both expressions need to be evaluated first.
    This is also not limited to Variants but applies to operator overloads as well (even if one of the operands is a boolean).

    FWIW: https://quality.embarcadero.com/browse/RSP-15470

    ReplyDelete
  5. And that also happens, if only one value being compared is variant.
    Something like:
    procedure Test;
    var
      X: Variant;
      O: TMyClass;
    begin
      X := True;
      O := nil;
      if (X = True) and (O <> nil) and O.IsSomething then
        DoSomething;
    end;

    Will always access O.IsSomething

    ReplyDelete
  6. Virgo Pärna That is not correct. The evaluation stops after the nil check for O.

    It would call IsSomething if you write:
    if X and (O <> nil) and O.IsSomething then

    because then one expression is of type Variant and thus all other expressions are being turned to a Variant. If you do (X = True) the result is of type Boolean and the short-circuit evaluation takes place.

    ReplyDelete
  7. Stefan Glienke
    Yeah, I might remember it incorrectly. But what is really strange, is, that I remember running into this problem. But right now I cannot create this problem. Weird. Even when using if X and (O <> nil) and O.IsSomething then

    ReplyDelete
  8. Ok, my problem was, that I assumed, that callin nil.IsSomething will result in Access Violation. When I changed test code to output message when IsSomething is called, then it started to show the issue.

    I guess the reason it works like this is, that in the case of Variant it does not know at compile time, if it is boolean or bitwise operation. So it needs to evaluate all values. But simply casting Variant to Boolean works.

    ReplyDelete
  9. Virgo Pärna Yes, the implicit type conversion is the problem. Because every boolean expression is being cast to variant to perform the boolean operator on two Variants. If you cast the Variant to a Boolean then the short-circuit evaluation can take place.

    ReplyDelete

Post a Comment