Delphi "WAT?!" of the day:

Delphi "WAT?!" of the day:

var
v1, v2: Variant;
begin
v1 := True;
v2 := True;
Writeln(v1 + v2); // -2
Readln;
end.

Comments

  1. And what did you expect? According to the documentation a boolean conversion to integer (via variant) is False = 0, True = all bits set to 1 (-1 if Integer, 255 if Byte, etc.) docwiki.embarcadero.com - Variant Types (Delphi) - RAD Studio

    ReplyDelete
  2. That's not so much a Delphi WAT as a COM one. VB (up to 6, and VBA) also interpreted True as -1.
    To be fair, it does make a kind of sense to have all the bits of True have the opposite value to the ones in False... In the case of Delphi, it's surprising since Ord(True) = 1.
    Then again, it's the kind of confusion you get when assigning different types of Variants to each other... (Why would you want to add two booleans, and what would you expect the result to be?)

    ReplyDelete
  3. The variant type was originally just a wrapper for OLE variants, and a boolean in OLE Automation is a two byte value where false = -1.

    ReplyDelete
  4. Martijn Coppoolse Well it wouldn't be unreasonable to expect + to act as OR (and * to act as AND)... but yea variants are kinda weird critters.

    ReplyDelete
  5. TBH the real WAT comes when you step through the code because it then goes through some float conversion when doing the addition.

    ReplyDelete
  6. Yet another reason to stay away from Variants as much as possible.

    ReplyDelete
  7. It does use _VarToDouble() in RealOp() but in that the Boolean->Integer is still done (for V.VType=varBoolean) with -1 as a result, which in turn is put into a double for addition. So even with the fact it does double addition... it has converted to integer first.

    ReplyDelete
  8. Although this might be considered a bug according to the documentation:
    var
    v1: Variant;
    r1: Real;
    begin
    v1 := True;
    r1 := v1;
    Results in r1 = -1 while the documentation says it should be 1. ("Boolean -> Real: False = 0, True = 1")

    ReplyDelete
  9. Rik van Kekem it wouldn't be the first time that documentation is wrong.

    ReplyDelete
  10. It's not a bug.

    What you see in the documentation is the conventional logic states for true/false for the "pascal type boolean," not as a boolean variant.

    So,

    showmessage(inttostr(ord(true)));

    and

    V1:=true;
    showmessage(V1); // this works

    will display 1 and -1.

    So what's the deal? The Microsoft OLE boolean for true is $FF, not 1. Thus to be compatible with COM objects the variant boolean for true must be $FF.

    This is old school stuff, going back more than 20 years with Delphi.

    ReplyDelete
  11. Jennifer Powell​​​ yes, but if you look at the conversion table in that documentation I mentioned it clearly stated that converting from boolean to real via variant it should be 1. While -1 from boolean to integer. So the documentation is clearly wrong. That conversion table is not for conventional conversion but especially for variants! It says "Variant type conversion rules". So, a bug in the documentation.

    ReplyDelete
  12. Oh OK, I see. Well, they made a typo in the docs - nothing new there of course. It is fair to say it's better to have bugs in the docs than in the code generator!

    ReplyDelete
  13. Rik van Kekem​ Delphi docs aren't very relevant here, this is a COM type

    ReplyDelete
  14. As David Heffernan wrote, this is a COM type, and the boolean for COM is a WordBool and not a pascal/Delphi boolean, with 0 or $ffff as values (not $ff Jennifer Powell) so the result is as expected.

    ReplyDelete

Post a Comment