45

I am working with some VB.NET code that seems to be casting a boolean value to an integer using CInt(myBoolean). The odd thing that is happening is that it returns -1 if the value is true. For example:

CInt(True)  // returns -1
CInt(False) // returns 0

Is this common in other languages?

I thought that a boolean would be 1 if true and 0 if false. Also, is there a way to make Visual Basic assign 1 to true instead of assigning -1?

svick
  • 236,525
  • 50
  • 385
  • 514
Barlow Tucker
  • 6,229
  • 3
  • 36
  • 42

11 Answers11

44

Typically, a value of false is represented by 0 and a value of true is represented by any non-0 integer value. The specific value for true and false (among others) are things that you shouldn't rely on - they can potentially be implementation specific. I'm not sure what you are trying to do, but it would probably be best to not rely on True or False having any specific integer values unless you absolutely have to.

The best explanation that I could find for VB's specific behavior comes from Wikipedia:

Boolean constant True has numeric value −1. This is because the Boolean data type is stored as a 16-bit signed integer. In this construct −1 evaluates to 16 binary 1s (the Boolean value True), and 0 as 16 0s (the Boolean value False). This is apparent when performing a Not operation on a 16 bit signed integer value 0 which will return the integer value −1, in other words True = Not False. This inherent functionality becomes especially useful when performing logical operations on the individual bits of an integer such as And, Or, Xor and Not.[4] This definition of True is also consistent with BASIC since the early 1970s Microsoft BASIC implementation and is also related to the characteristics of CPU instructions at the time.

Martin Mulder
  • 12,642
  • 3
  • 25
  • 54
Thomas Owens
  • 114,398
  • 98
  • 311
  • 431
  • 2
    I just tested this premis. A boolean in VB.NET does not equal `-1`, it equals just `1`. I checked this by making a structure with two overlapping fields using FieldOffsetAttribute. That way you can see the exact binary value of a boolean. `CInt` is just a conversion. Refering to old documentation does not really help I guess. – Martin Mulder May 09 '13 at 15:07
  • 3
    I passed `True`into a function that accepted an integer and got the value `-1` in VB.NET. In the article Martjin references (http://msdn.microsoft.com/en-us/library/ae382yt8.aspx) it seems like how you convert the Boolean determines what integer value you get. – Brian J Oct 18 '13 at 15:05
13

A work around for your initial use would be :

 Dim i As Integer = CInt(Int(False))

This will return a 0.

 Dim i As Integer = CInt(Int(True))

This will return a 1.

Msonic
  • 1,456
  • 15
  • 25
Michael Eakins
  • 4,149
  • 3
  • 35
  • 54
  • 3
    Doesn't work for me. CInt() returns signed integer, so I got -1 again. May be this is an old solution (I use VBA 7.1) – AlexL May 31 '19 at 10:11
  • 1
    This only happens in VB.NET, and what does it is the [`Int()` function](https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualbasic.conversion.int?view=net-6.0#microsoft-visualbasic-conversion-int(system-object)) whose behaviour was silently changed. It returns -1 in VB/A . – GSerg Sep 10 '22 at 08:04
  • @GSerg if you notice 12 years ago the OP stated they were using VB.NET, not VBA. While they are similar that may be why it isn’t working for you. – Michael Eakins Sep 10 '22 at 16:43
9

It seems like a gotcha, and I don't know any other examples of this behaviour.

Troubleshooting Data Types (Visual Basic) specifies this behaviour, with a "Don't do that, mkay" sorta remark with it. Do note further down:

Conversion in the Framework

The ToInt32 method of the Convert class in the System namespace converts True to +1.

If you must convert a Boolean value to a numeric data type, be careful about which conversion method you use.

Andrew Morton
  • 24,203
  • 9
  • 60
  • 84
Martijn
  • 11,964
  • 12
  • 50
  • 96
5

I had the same problem and used Math.Abs function on the result :)

antyrat
  • 27,479
  • 9
  • 75
  • 76
marco
  • 51
  • 1
  • 1
4

Many versions of BASIC in the 1970's and 1980's implemented bit-wise arithmetic with their AND and OR operators, and made true conditional expressions evaluate to -1 (i.e. the "all-bits-set" value in the two's complement used for integers). I'm not sure exactly why the decision was made to have true conditional expressions evaluate to an all-bits-set value; being able to use AND to mask an integer against a conditional expression may have been faster than multiplying, but given then internal mechanics of the interpreters the difference would have been slight.

In any case, the first versions of BASIC that Microsoft produced for the PC followed in that tradition of having true conditionals evaluate to -1 (all-bits-set); since QuickBASIC was in turn supposed to be compatible with those, and Visual Basic was supposed to be compatible with QuickBASIC, they used the same representation. Although .Net recognizes integers and Booleans as different types, VB.Net wanted to offer a migration path for VB6 programs that might rely on the old behavior. With "Option Strict Off", VB.Net will implicitly convert a Boolean value of True to an integer -1; while most programmers use Option Strict On, it would be confusing to have the behavior of CInt() differ from the implicit conversion behavior.

supercat
  • 77,689
  • 9
  • 166
  • 211
3

I tested it and got the following results:

Public Module BooleanTest
Public Function GetTrue() As Boolean
    GetTrue = True
End Function
End Module

...

[StructLayout(LayoutKind.Explicit)]
struct MyStruct
{
    [FieldOffset(0)]
    public bool MyBool;
    [FieldOffset(0)]
    public int MyInt32;
}

static void Main(string[] args)
{
    MyStruct b1, b2;
    b1.MyInt32 = 0;
    b2.MyInt32 = 0;
    b1.MyBool = BooleanTest.BooleanTest.GetTrue();
    b2.MyBool = true;
    Console.WriteLine(b1.MyInt32);
    Console.WriteLine(b2.MyInt32);
}

This will result in:

1
1

I hope this proves that all True values inside .NET are always the same. The reason is simple: All .NET members have to communicatie with each other. It would be weird if object.Equals(trueFromCSharp, trueFromVB) would result in false (as will trueFromCSharp == trueFromVB).

CInt is just a function which will convert True into -1. Another function Int will return 1. But these are converters, and do not say anything about the binary values.

Martin Mulder
  • 12,642
  • 3
  • 25
  • 54
2

I have been having the same problem with MySQL as this has no Boolean type only a tinyint(1).

My solution was to write a converter function to ensure that the values are correct before inserting them into the database

        Public Function BoolToMySql(bVal As Boolean) As Integer
            Dim retVal As Integer
            If bVal = True Then
                retVal = 1
            Else
                retVal = 0
            End If
                 BoolToMySql = retVal
        End Function
Roger
  • 21
  • 1
1

I hope that is can help others work with Booleans inside VB.NET. Just as a better way to write the VB.NET that Roger wrote:

Public Function BoolToMySql(bVal As Boolean) As Integer
   return  If(bVal, 1, 0)
End Function
John Grabauskas
  • 310
  • 2
  • 5
0

I found the other answers lacking for the specific VBA scenario I was working with. This is not tested in VB.NET.

I wanted to take any given number that was <> 0 and make it 1, and keep 0 as 0 in a single line of code, without an If statement. The way that I ended up doing this, which I did not see in other given answers, was:

Abs(CBool(iCount))

CBool() converts the given number (iCount in example above) to Boolean, narrowing the possible results to two values; True with a value of -1 and False with a value of 0.

Abs() then takes the absolute value (no negatives) of the Boolean to return 0 for False and 1 for True.

In practice, the following return 0:

Abs(CBool(0))
Abs(False)

And the following return 1:

Abs(CBool(1))
Abs(CBool(-1))
Abs(CBool(-38473))
Abs(CBool(358677))
Abs(True)

I hope that this is useful for anyone else playing with specific scenarios such as this.

Dustin
  • 25
  • 7
0

I may be a bit late but here's a simple workaround to receive the typical 1 for True and 0 for False.

Multiply the boolean with -1 like so:

CInt(True) * -1
CInt(False) * -1

Which then returns

1
0

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Aug 12 '22 at 20:57
  • And it doesn't *explain* anything, as is asked. – Gert Arnold Aug 14 '22 at 17:48