Monthly Archives: May 2004

The “native” .NET language?

In the comments on my post on language choice, Patrick asked “isn’t C# the language that’s most ‘native’ to the .NET environment?” Christopher then follows up with a related question as to whether developers should use functions in the System namespace instead of ones in the Microsoft.VisualBasic namespace because the former might be faster. We see these kinds of questions fairly often, so it’s worth discussing them a little bit.

Before going any further, I’d recommend that people who have questions like this take a look at an article that Derek Hatchard and Scott Swigart wrote for MSDN entitled “Visual Basic .NET Internals”. It looks at a bunch of these issues in detail and is an excellent place to start on this question.

The bottom line, though, is that there is no language that is ‘native’ to the .NET environment. While it’s certainly true that there was no language called ‘C#’ that existed before .NET came into being, one of the major selling points of C# is that it is an amalgm of the syntax and features found in C, C++, Java and VB, adapted for the .NET platform. In that sense, it is exactly like Visual Basic on .NET – an adaptation of a previously existing language (just as C++ and Java were, in turn, adaptations of C, which was, itself, an adaptation of prior languages). Both C# and VB were designed to work well with .NET, and developers can choose either language without any concern about access to the fundamental capabilities of the .NET platform, because they both compile down to IL in the end. The only differences you’re going to see between the IL the two languages generate is when one language does something more for you than the other language does (or we have a bug, in which case, let us know about it).

The question of the Microsoft.VisualBasic namespace is similarly straightforward. The base class libraries (i.e. the System namespace) provide a huge amount of functionality which both C# and VB give you full access to. The functions in the Microsoft.VisualBasic namespace are built directly on top of the System namespace and provide functionality that goes above and beyond the functionality that the System namespace provides. As such, there is no real reason not to use the functions there because they provide you “all the features of the class libraries and more.” (And we’re going to go even further in VB 2005.) Having said that, there may be situations in which you may want to sacrifice some of the extra functionality for a little more performance. This is the same kind of tradeoffs that you have to make with the System namespace, and so if performance is critical, it’s always important to understand the functions that you’re calling (the paper linked to above talks a lot about this).

The problem with blanket pronouncements like “always use CLR functions instead of VB functions“ is that you can easily shoot yourself in the foot without knowing it. One suggestion I’ve seen in more than one place is to use the functions exposed by the Convert class (a CLR class) instead of the intrinsic conversion operators (CInt, CStr, CLng, etc.) exposed by the VB language. This is supposedly because the CLR functions are going to perform better than the VB “functions.” The problem with this is that the conversion operators are true operators that compile down to IL instructions while the Convert functions are still just functions. This means you’ll get significantly worse performance by calling Convert.ToInt32 instead of using CInt. So it’s always very important to know what you’re doing when you start tackling issues like performance.

So, in the end, there is no “native” language on the CLR and performance is something you’re going to have to think about no matter what language you choose. (In fact, I think I should add a rule #0 to my “Ten Rules of Performance:” When it comes to performance, beware rules.) There are certainly lots of other factors to think about when choosing between VB and C#, but I don’t think these are two of them.

Send us those Watson reports!

I would have to second Cyrus’s request for everyone to send us Watson crash dumps when you run into problems. Watson is an invaluable tool for finding squirrly bugs that may be difficult for us to reproduce or require configurations that, for some reason, we don’t test. I will also add that debugging a Watson crash dump is a big pain in the rear, so you can also take some perverse pleasure in the fact that whoever introduced the bug in the first place is going to have to suffer to fix it. (I confess that sometimes I get a little jolt of satisfation on this as a user when I’ve hit some particularly bad crash.)

Interestingly, in VS 2002 and VS 2003, the VB compiler itself won’t report most crash dumps. That’s because Watson normally works by catching unhandled exceptions that escape out into the system. The problem with this is that after Watson finishes collecting its crash information, it really can’t do anything but kill the offending process, so you lose everything you’ve got in the IDE at that point. So instead of having compiler crashes result in losing everything, the VB compiler catches all of its own exceptions and gives you a dialog that says, in effect, “Something bad really happened. Save all your work and restart the IDE.” Since we never let any exceptions escape out into the system, Watson never gets involved. (I believe the C# compiler does the same thing in VS 2002 and VS 2003.)

For VS 2005, Watson has been enhanced to allow us to invoke it without actually having to kill the application. So going forward, VB will give you a Watson dialog to let you report the crash and then let you save your data. So we expect to get a lot more Watson reports this time around, which is a good thing. (As a side note, in VS 2002 and VS 2003, we did allow exceptions to escape to Watson during the betas so we could get better beta information. It was just suppressed in the released retail version.)

Interestingly, one of the handful of features that I actually implemented in VB 2005 was enabling this Watson reporting…

Should I move from VB6 to VB .NET or C#?

TechEd 2004 was crazy busy, so there’s going to be some catch up time before I get back into full swing blogging. However, one thing I did want to relate before I forget it.

Last night, Duncan Mackenzie, Amanda Silver, Steven Lees and I (the middle two are VB Program Managers) were having dinner at TechEd and we started discussing the logic of a statement made by several customers during the conference that boiled down to: “We figured that since VB .NET wasn’t the same as VB6, we might as well move to C# when we moved to .NET“ After thinking about this for a moment, it occured to me that this is somewhat akin to saying:

“We figured that since British English wasn’t the same as American English, we might as well learn German when we moved to Europe.”

I mean, it’s a free country and all, but the logic of this does seem a little, well, illogical. Although the two languages can do many of the same things and have many similarities, taking on the extra burden of doing the cultural retraining necessary to move from VB to C# without some kind of well-researched rationale seems to me to be doing a whole lot of work that you don’t really need to. VB .NET adds a lot of power to VB and tweaks a few familiar things, but it’s still substantially the same language, just in the same way that British, American, Canadian and Australian English are all the same language, even if three out of four insist on using “u“s in funny places. (Although on the plane ride back, I got stumped on a crossword because I wrote in “lustre“ rather than “luster.“ I guess I watched too many British shows on PBS growing up.)

The way of the world, I guess, but it doesn’t make sense to me…

Why aren’t Try variables in scope in the Catch or Finally?

Bill McCarthy recently asked me a question that’s come up a number of times both internally and externally: why can’t a Catch or Finally block access local variables declared in a Try block? In other words, why doesn’t the following work?

Try
    Dim i As Integer = 5
Finally
    Console.WriteLine(i)
End Try

There are four answers to the question: the practical answer, the simple answer, the complex answer and the real answer.

THE PRACTICAL ANSWER: The question is moot because changing it now would potentially break code by changing the binding path. For example:

Class Foo
    Private i As Integer
    Sub Bar()
        Try
            Dim i As Integer
            Throw New NullReferenceException()
        Catch
            i = 5
        End Try
    End Sub
End Class

THE SIMPLE ANSWER: Catch and Finally blocks are not children of the Try block, they’re siblings. You can see this by the indentation style and by convention. And the normal scoping rules are that sibling blocks cannot see each other’s locals.

THE COMPLEX ANSWER: You can still say “Yes, but you could still have made an exception in this case, right?” True. However, requiring Catch/Finally variables to be placed outside of the Try block generally results in better code by emphasizing the initial state of the variable (since an exception can occur almost at any time, so the initial state is the only thing you can assume). For example, the following code has a bug — if the File constructor throws an exception, then the Close call is going to throw one too.

Try
    Dim F As File = New File(“foo.txt”)
    F.Read(…)
Finally
    F.Close()
End Try

THE REAL ANSWER: You may find both of these arguments unpersuasive, which is fine — a quick search on Google quickly found similar debates around Java and I’m sure other languages have them too. The real answer is that it’s a judgment call and certainly one that we’ll probably be arguing about from here until eternity…

Attributes, CLS compliance and VB 2005

Since I’m answering questions today, I might as well address Robert‘s question as to why VB doesn’t support attributes that take 1-dimensional arrays. Actually, not only does VB not support attributes that take 1-dimensional arrays, we also don’t support attributes that take parameters typed as Object. So why not? Time, mostly, but the CLS comes in to play here as well.

Attributes that take 1-dimensional arrays and Object are not CLS compliant, as per CLS rule #34 (see pg. 118 of Jim Miller’s excellent Common Language Infrastructure Annotated Standard book). Interestingly, though, the C# compiler does not warn you when you declare attribute constructors that use the non-CLS compliant types but you declare your assembly to be CLS compliant. My take on it is that they have a bug in their compiler and that they should warn you. However, I suspect they might also make a claim that the vague wording of the rule makes their compiler behavior correct – the rule states that other types cannot be “encoded,” so I guess they could argue that it’s not the attribute definition that’s non-CLS compliant, but some theoretical use of it. However, the CLS rules generally talk about prohibit you from declaring something non-CLS compliant not using something that’s non-CLS compliant, so I’m not sure I would lend this argument (if, indeed, they actually wanted to make it) much credence.

Anyway, language lawyering aside, the issue was that attributes came online very late in VB 2002, and we ended up not support 1-dimensional arrays and object values in attributes for time reasons. We figured it wouldn’t be that big of a deal because, hey, they’re not CLS compliant! Of course, since there’s no warning from the C# compiler about using these types in attributes, people expect them to work in VB and, when push comes to shove, the CLS argument just isn’t very satisfying. Which is all a long way of saying that we’re supporting them in VB 2005.

And I’m going to have to go now and test to see whether we give you a CLS warning…