About 8 months ago, I promised to explain why the C# ‘as’ operator was worth adding to VB and then never got back to it. While trying to figure out what comments I missed, I came across the promise again and figured I’d take the opportunity to rectify the situation.
In Whidbey, we’re going to introduce YACO (Yet Another Conversion Operator) called TryCast that’s equivalent to the C# ‘as’ operator. Why? It turns out that it’s useful in some specific, but not uncommon, situations. Let’s say that you want to write a method that accepts an object and, if it implements a particular interface, do something with it. For example:
Sub Print(ByVal o As Object)
Dim PrintableObject As IPrintable
If TypeOf o Is IPrintable Then
PrintableObject = DirectCast(o, IPrintable)
PrintableObject.Print()
End If
...
End Sub
Ok, great, this works fine. The problem is, though, that we’re doing redundant work here. You see, when the CLR executes the If statement, it does a type check for the TypeOf expression. If o does implement IPrintable, it then goes ahead and casts o to IPrintable, which does another type check to ensure that the value really does implement IPrintable. So you’re doing two type checks, and type checks can be expensive. (When I say “expensive” here, I don’t mean expensive like “$760,000 for a Ferrari” expensive, I mean more like “$3.50 for a latte twice a day adds up over 365 days” expensive.)
What TryCast does is it allows you to combine the two type checks into one. TryCast, as its name suggests, will try the cast and, if it succeeds, return the value cast to that type. Otherwise, it returns the value Nothing. So you can rewrite the code above as:
Sub Print(ByVal o As Object)
Dim PrintableObject As IPrintable = TryCast(o, IPrintable)
If PrintableObject IsNot Nothing Then
PrintableObject.Print()
End If
...
End Sub
Voila, two type checks becomes one! Even if we hadn’t gotten any feature requests for this, we were planning to do it anyway because we found that several of our language helpers that deal with object values could be sped up ~5% just by eliminating the redundant type checks. So it’s not nothing. (So to speak.)
One question that might come to mind is: why not just optimize the first code into the second code under the covers instead of introducing a new operator? We did consider this at the compiler level, and the CLR could also choose to do it at the JIT level. However, while we could optimize this particular case, it’s easy to construct cases that would be difficult for the compiler or JIT to optimize. Which would mean that you could make a minor tweak to the structure of your code and suddenly lose the optimization without knowing it. In this case we figured explicitness was better…
Update 4/3/04: Made some corrections based on comments below.