Last week, Rachel posted an
entry talking about
AndAlso and OrElse. Besides Integer and array bounds, this has got to be one of
the most sensitive changes we made to the language in VB .NET 2002. So I thought
I'd talk a little bit about it.
Prior to VB.NET, the VB language only had the And and Or operators. They were
essentially bitwise operators, which means that they took their two operands and
performed an AND or OR operation on each bit position to produce the resulting
bit. So 3 Or 4 = 7, and 2 And 4 = 0. At the same time, the Boolean value True
was considered to be equivalent to the value -1, which is just a 1 in each bit
position. As a result, the bitwise operators behaved as if they were logical
operators when working on Boolean values. So True And False = False, and True Or
False = True. And if you mixed and matched Boolean and numeric values, things
pretty much worked the way you'd expect them to. So True And 4 = 4, and 10 Or
False = 10.
This all worked pretty well, and avoided the situation you have in languages
like C where there are separate logical operators (|| &&) and bitwise operators
(| &). However, there were some problems. The biggest was that it was not
possible to support short-circuiting behaviors when doing logical AND and OR
operations. Short circuiting is fantastically useful, especially when dealing
with reference types. It is extremely common to want to write code along the
lines of:
If (Not x Is Nothing) And (x.y = 10) Then
...
End If
Without short circuiting, though, this code will throw an exception if x is
Nothing, because both sides of the operation are always evaluated. (Having
learned about the usefulness of short circuiting from other languages, this
limitation bit me all the time when I was working in VB, and I even saw quite a
few bugs like this created by people who knew nothing about short circuiting but
just expected it to "do the right thing.")
One of the things we wanted to do in VB.NET, then, was add short circuiting
logical operations. A way of doing it would have been just to have changed the
meaning of And and Or if the two operands were typed as Boolean, but this seemed
a very unacceptable solution. In general, it is very bad to overload two very
different behaviors on top of the same keyword. In other words, without knowing
what the result type of Foo() and Bar() were, it would be hard to know what
the behavior of
If Foo() And Bar() Then
...
End If
would be. Would Bar() always be evaluated or would it sometimes not be
evaluated? Even worse, the behavior of the expression might change drastically
by shifting the type of just one of the operands.
The only other alternative, then, was to introduce new operators. Our first
thought was that logical operations are much more common than bitwise
operations, so we should make And and Or be logical operators and add new
bitwise operators named BitAnd, BitOr, BitXor and BitNot (the last two being for
completeness). However, during one of the betas it became obvious that this was
a pretty bad idea. A VB user who forgets that the new operators exist and uses
And when he means BitAnd and Or when he means BitOr would get code that compiles
but produces "bad" results. For example:
If 2 And 4 Then
...
End If
Assuming Option Strict was off, this would produce the value True (or -1)
instead of the value False (or 0), as it did in previous versions. Given that this would
be a very easy error for programmers to make and it would have an effect
that could be very hard to track down and understand, it seemed clear to
us that changing the meaning of these operators would be untenable.
That left the option of adding new logical operators, and we spent a lot time
thinking about potential new keywords. I think I'll do a whole entry later just
on the question of choosing new keywords, but suffice it to say that AndAlso and
OrElse were the best choices, in our humble opinions. Ironically, we're not even
the first language to use those names in this way - the functional language ML
has andalso and orelse operators, too. (I don't think we were aware of that at
the time we were choosing the keywords, although I could be wrong about that.)
People seem to enjoy
poking fun at the
keywords, but after working with them for a while, I think they work pretty well
and were the right way to add the new feature to the language without breaking
people in bizarre and unexpected ways. Then again, as always, I'm biased...
[Correction 09/15/03: Fixed small math error pointed out by Stuart, below.]