delphi

Why does true variant booleans become -1 when cast to an integer?


I realise that one should not expect true Booleans to become 1 when cast to an Integer, purely that they become non-0.

However, the result changes depending on whether the variable is a Variant (but varBoolean) or a Boolean.

Consider the following:

I := Integer(true);

I is now 1.

But...

var
  I: Integer;
  V: Variant;
begin
  V := true;
  I := Integer(V);
end;

I is now -1.

Of course, if I cast V to a Boolean before casting the resulting Boolean to an Integer, I becomes -1.

But I am curious as to why that is.

Is this because of the way that Booleans are stored (say as 1 bits), and when casting to an Integer, Delphi performs a conversion, which does not occur when casting a Variant to Integer?

I only bring this up, because if you are used to a true Boolean casting to 1, it can be dangerous to have varBoolean share case with varInteger in a VarType()-case.

For instance:

case VarType(V) of 
  varInteger, varBoolean: I := Integer(V);
end;

Would not behave as one might expect.


Solution

  • The behaviour is indeed as expected. The varBoolean type corresponds to VT_BOOL. Which is documented like this:

    VT_BOOL

    A Boolean value. True is -1 and false is 0.

    You also say that Delphi's boolean is stored as 1 bit. That's not actually true. They are stored in a single byte, 8 bits. I suppose the key point is that a VT_BOOL variant does not contain a Delphi Boolean. The VT_BOOL variant is a different beast altogether, dating originally from VB. Raymond Chen discusses this a little here: BOOL vs. VARIANT_BOOL vs. BOOLEAN vs. bool