Compartilhar via


Not Logical Is VBScript

Quick, what's the difference between

If Blah = True Then Print "True!" Else Print "False!"

and

If Blah Then Print "True!"

Else Print "False!"

Is there a difference?

Yes, there is a big difference. If

Blah is True or False, then both statements do what you'd expect -- the same thing. But the thing is, the first statement basically says "is Blah equal to True?" whereas the second says "is Blah not equal to False?" In a strictly Boolean world, those are equivalent because of the Law Of The Excluded Middle. But the VBScript type system is richer than just Booleans!

For example, what if

Blah is the string "True"? The string "True" is not equal to the Boolean True, so the first statement is false. But the string is also not equal to False, so the second statement is true, and therefore the statements have different semantics.

(ASIDE: But hold on a minute --

Print "True" = True prints out True. Yet I just said that they weren't equal. What's up with that? That's a subject for another entry!)

The same goes for numbers. When converted to a number,

True converts to -1 (for reasons which will become clear in a moment) and False converts to 0. Therefore, if Blah is 1, again the first statement is false because 1 <> -1, and the second statement is true because 1 <> 0.

It gets weirder. In JScript you can do something like this:

if (blah != null && blah.frob == 123)

and it works just fine. But in VBScript

If (Not Blah Is Nothing) And (Blah.Frob = 123) Then

Then if

Blah actually is Nothing, this still crashes and dies, whereas JScript does not. What the heck is going on here?

What's going on is that VBScript is not logical. VBScript is bitwise. All the so-called logical operators work on numbers, not on Boolean values!

Not, And, Or, XOr, Eqv and Imp all convert their arguments to four-byte integers, do the logical operation on each pair of bits in the integers, and return the result. If True is -1 and False is 0 then everything works out, because -1 has all its bits turned on and 0 has all its bits turned off. But if other numbers get in there, all bets are off.

JScript has both logical (

&&, ||, !, etc.) and bitwise (&, |, ~, etc) operators, but VBScript only has bitwise operators. That means that JScript can do lazy logic. In Jscript, when the first half of the and-expression evaluates to false, it knows that it should not evaluate the second half for the logical operator but it should for the bitwise operator. In VBScript, both halves are always evaluated.

(ASIDE: VB.NET has added lazy logic operators, at long last.)

This can lead to some strange situations if you're not careful. In VBScript, it is certainly possible for

If Blah Then

and

If Foo Then

to be both true, but

If Blah And Foo Then

to be false -- if

Blah is 1 and Foo is 2, for example.

Given these potential "gotchas", what's the right thing to do? Here are my opinions of some best practices.

Conditional statements should always take Booleans. Or, in other words, use Booleans as Booleans, use nothing else as Booleans.

Suppose you've got a method that returns a number and you want to do something if it doesn't return zero. Don't do this, even though it does exactly what you want:

If Foo.Bar(Blah) Then

it's clearer to call it out and make the conditional take a Boolean:

If Foo.Bar(Blah) <> 0 Then

Conversely, if a value is a Boolean and you know that, there's no need to compare it. When I see

If Blah = True Then

what I think is that

Blah might contain something other than True or False. If Blah can only contain True or False, then just say

If Blah Then

Similarly with the "logical" operators. Don't mix-n-match -- either every argument should explicitly be a number, and you're doing bitwise comparisons, or every argument is a Boolean. Mixing the two makes the code harder to read and more bug-prone.

Comments

  • Anonymous
    July 15, 2004
    If you've ever lost a monitor to VBScript (from frustrated punching, mine has dents), Eric Lippert provides some solace in that there's at least a reason why it behaves that way. In JScript you can do something like this: if...

  • Anonymous
    July 15, 2004
    People might find more about how this works under "short circuit evaluation" instead of "lazy logic". Interestingly, if you're feeling lucky about "short circuit evaluation" you might end up on the KB article discussing this change in VB.NET.

  • Anonymous
    July 15, 2004
    Eric, what's your suggestion as an alternative for something like:

    If (Not Blah Is Nothing) And (Blah.Frob = 123) Then

    Nested Ifs?

  • Anonymous
    July 15, 2004
    The comment has been removed

  • Anonymous
    July 15, 2004
    >> What's going on is that VBScript is not logical. VBScript is bitwise.

    So does that mean is someone is not being logical, they are being bitwise? And conversely, that if they are being logical they are definitely not being bitwise?

    >> Conditional statements should always take Booleans. Or, in other words, use Booleans as Booleans, use nothing else as Booleans.

    Well, duuuuh! Oh, sorry, I forgot there are also C-language types in this world. :)

  • Anonymous
    July 15, 2004
    > So does that mean is someone is not being logical, they are being bitwise

    That's a very bitwise question.

  • Anonymous
    July 16, 2004
    Personally, I like being a bit foolish type.

    Oh, the ironicity...

  • Anonymous
    March 22, 2007
    Genius!!!!! You saved me from growing gray hair! Thx, ~J

  • Anonymous
    April 22, 2007
    The comment has been removed

  • Anonymous
    January 21, 2009
    PingBack from http://www.keyongtech.com/1949224-if-bpigscanfly-false-i-get