IsNot and the fall of civilization

Back when I said that Whidbey is going to be introducing an IsNot operator, Karl raised some objections to the operator in the comments, to which I said:

Karl, it seems like your question isn’t so much why we’re adding “IsNot” but why we have “Is” in the first place. It’s a good question, I’ll try to address it in an entry soon.

…and then I never came back to it. Now that Daniel has picked up the thread again, let me return to the subject and elaborate just a little bit.

As I said in the comments, the question that Karl and Daniel raise is not so much “why IsNot?” but instead “why Is?” The fundamental reason for adding IsNot was that it’s irritating to have a comparison operator and not its inverse. For example, it’s entirely feasible to have a language with just Not, =, < and <=, but no language bothers to be “pure” that way because it’s a PITA to have to write “If Not x = 5 Then” or “If Not x <= 5 Then” and so on. Given the existence of the “Is” operator, having its opposite seems like, as Martha would say, “a good thing.” Charges of language pollution seem, on the face of it, to be a stretch.

OK, so let’s leave aside the question of IsNot for a moment. Why bother to have two comparison operators, “Is” and “=“? There’s a historical reason and a modern reason. The historical reason is that, prior to VS 2002, VB allowed classes to define a parameterless default property that represented the “value” of the class. This feature allowed, say, a TextBox object to declare that its Text property was its “value” property and then the user could write “TextBox1 = “foo”” and it would assign the string value “foo” to TextBox1.Text. However, since a class could be both an object and a value, you needed to have two forms of comparison and assignment to distinguish between the two. Assignment was handled by splitting it into “Let” vs “Set” assignment: “Let TextBox1 = “foo”” assigned a value to the default property, while “Set TextBox1 = New TextBox()” assigned a value to TextBox1 itself. Comparison was handled by splitting it into, yes, you guessed it, “=” and “Is”. The code “TextBox1 = “foo”” would do a value comparison between the string value “foo” and the default property TextBox1.Text. The code “TextBox1 Is TextBox2”, on the other hand, would do an object comparison between two TextBox objects.

When we made the leap to .NET, though, we ran up against a bit of a wall. Other languages such as C# and C++ didn’t support the concept of parameterless default properties, two types of assignment, two types of comparison, etc. This wasn’t a big deal for fields, but it was a huge issue for properties – whereas a VB property could define a Get, Let and Set, a C# property could define only a Get and a Set. We spent a lot of time trying to invent ways to map between the two schemes and finally came to the conclusion there was no good mapping. (Even today this is one of the friction points between COM and .NET that can make interop a pain.) So we gave in and dropped parameterless default properties from the language. This meant that we could also drop Let vs. Set assignment from the language. And, if we’d chosen too, we could have dropped “Is”. But we didn’t…. Why is that? Two reasons, one minor, one major.

The minor reason is that we could produce more optimal comparisons between values typed as Object (if someone’s really interested in this, I can explain, but it’s kind of obscure). The major reason was that we were anticipating a feature that didn’t make it into VS 2002 or VS 2003 but will make it into Whidbey: operator overloading. Take the situation where you’ve got a class that overloads the equality operator:

Class ComplexNumber


Public Shared Operator = (ByVal c1 As ComplexNumber, ByVal c2 As ComplexNumber) As Integer

End Operator
End Class

Now, when you say “c1 = c2“, you’re always going to get value equality between two ComplexNumber instances, not reference equality. But let’s say that you really need to know whether c1 and c2 are the same instance not just the same value. How do you do it? In VB, it’s simple. You say “If c1 Is c2 Then…“. What do you have to do in C#? You have to make sure you cast both values to object and then do the comparison: “if ((object)c1 == (object)c2) {…}“. Forget the cast, and you’ve accidentally slipped back into value comparison.

So that’s why we kept “Is“ and “=“. And, yes, I think this is one of the places where our syntax is clearer than C#’s. Although everyone’s free to disagree…

21 thoughts on “IsNot and the fall of civilization

  1. Cory Smith

    [whistles][cheers][whistles][cheers]

    I’ve definately got to keep this one on my list of things to point out how a verbose langauge can be a good thing ;-)

    One point though, can’t you use the .Equals method instead of casting (in VB.NET or C#) to accomplish the same task as ‘Is’? It seems cleaner than the casting, so I figured just to be fair, it deserves mentioning ;-)

    Keep up the great work!

    Reply
  2. Cory Smith

    Doh!, I guess I should’ve looked it up before suggesting .Equals… looks like you still have to cast since it test for the value not the reference. Well, that’s what I get for trying to defend that other language ;-)

    Reply
  3. Karl

    Thanks for the explanation Paul. I image all language teams faced some pretty unique challenges when moving forward to .Net. I bet you guys (vb.net) had the hardest job: bringing VB in line with other full blown languages, while maitaining what made VB so popular to begin with. I think you guys did a great job, and while I still question some parts of the language, overall its a great language to work with, and thanks to the framework, it’s capable of doing anyhting other languages can.

    I know whidbey is a pretty big release for all languages, and I’m glad to see VB.Net isn’t going to be lagging behind at all. I can’t wait to overload the IS operator and screw up some expected behaviour! :)

    Reply
  4. Pingback: VS DATA Team's WebLog

  5. Pingback: Enjoy Every Sandwich

  6. Frans Bouma

    Besides the discussion of ‘is’ vs. ‘=’ (SQL also has WHERE foo IS NULL instead of WHERE foo = NULL) I think an IsNot is appropriate.

    Doing a lot of C# -> VB.NET porting I know a lot of quircks of VB.NET, (these are template files, so I have to do these without intellisense also), and one of them is the If Not var Is Nothing Then construct, which is totally different from the C# if(var!=null) construct. It feels awkward. I think IsNot is a good achievement, so you can say: If var IsNot Nothing Then…

    VB.NET then has to solve the problem of course with:
    If Not var = 4 Then… because that constuct is different from the object reference test, or is IsNot also usable for non-object references? (I truly think it has to)

    Reply
  7. Frans Bouma

    "VB.NET then has to solve the problem of course with:
    If Not var = 4 Then… because that constuct is different from the object reference test, or is IsNot also usable for non-object references? (I truly think it has to)"
    is of course not true, you can just say <> instead of not bla = value. My bad. (I haven;’t had coffee yet… *ugh*)

    Reply
  8. Pingback: Code/Tea/Etc...

  9. Dewayne Christensen

    So much negativity! I say we add a Something keyword:

    If myVar Is Something Then
    ShareTheWealth(myVar)
    End If

    Reply
  10. Pingback: AddressOf.com

  11. funsho

    Why can’t we add is "Something" Keyword !!!

    like this

    if Mycode is Something Then
    MyError(callimg)
    End if

    i.e if there is something in the Variable Mycode,
    it should call the the function MyError.

    Reply
  12. Corrado Cavalli

    funsho,
    Hope you’re joking, in VB.NET we have so many keywords and C# can do the same (sometimes better) with less…

    Reply
  13. David V. Collins

    I’m glad to see this coming. I’ve been coding:

    If x Is Nothing = False

    All this time, just to avoid having to put the Not at the front.

    Reply
  14. Eric Mutta

    An small but useful addition :-).

    Another thing to consider Paul. When operator overloading comes, if we are allowed to overload the bitwise Not operator, then code like:

    If Not x Is Nothing Then

    will become ambiguous and possibly need a change to the precedence rules. it could mean:

    If Not (x Is Nothing) Then

    or

    If (Not x) Is Nothing Then

    both of which are totally different in semantics. This could cause a lot of old code to silently work incorrectly if one overloaded the Not operator…you’ll probably need an upgrade that converts code to use the IsNot operator to avoid this dilemma.

    Reply
  15. Eric Mutta

    I would be interested to know how you "could produce more optimal comparisons between values typed as Object…", if you have some time to explain :-)

    BTW, your task in designing VB is a hard one..I applaude you and your team for the great work you’ve done thus far..good stuff! :-)

    Reply
  16. paulvick

    Eric: Operator precedence places Is higher than Not, so it’s always evaluated as Not (x Is Nothing) and operator overloading can’t change that. Using Is is a little more optimal for reference comparison because we know for sure that you’re doing reference comparison and not doing value comparison of two values cast to Object. For example, CObj(1) = CObj(2) is a legal expression and requires calling a helper. But with Is, we can skip the helper call because we know we’re doing reference comparison. Not sure if that makes sense, but it’s about all I can do in a comment… Thanks!

    Reply
  17. Akem

    Doh!, I guess I should’ve looked it up before suggesting .Equals… looks like you still have to cast since it test for the value not the reference. Well, that’s what I get for trying to defend that other language ;-)

    Reply
  18. Pingback: Panopticon Central

  19. Matt

    On the "VB is clearer than C# syntax" issue, i agree – the casting is a mess.. But perhaps Java has it clearest of all:

    For object reference types, == always compares references and .Equals compares values.

    For value types (primitives like bool, int, long), == effectively compares value because they are indistinct from the reference they are tied to

    One thing i really disagree with in VB is, if i write in the immediate window:

    ?Nothing = Nothing

    True

    I dont think this should be true. I dont even think it should be allowed syntax. If = is charged with the task of comparing values rather than references, then it shouldnt produce a true if both values are unknown.

    One rule to ring them all.. :)

    Reply

Leave a Reply