Category Archives: Visual Basic

Bay .NET User Group talk, February 12th

Something that I think I’ve forgotten to mention up until now (shame on me!): I’m going to be giving a talk on VB .NET 2.0 at the Bay .NET User Group this Thursday, February 12th. The show starts about 6:45pm and should run for about an hour and a half – more details can be found at the Bay .NET User Group page. Even though the blurb I wrote claims that I’m going to focus entirely on the language, I’m thinking I may talk about some IDE features that relate as well. Should be a good talk.

(I think that Addison-Wesley may also be sending along some pre-production copies of my book for raffling! Just a few more weeks until the real thing comes along!)

DevDays are coming!

Just wanted to make a quick plug for the upcoming DevDays presentations across the US. It’ll be a great event with lots of good information (and another chance to get a copy of the Whidbey technology preview!) and the smart client track is all going to be in VB.NET. Be there or be rectangular!

What does /optimize do?

Cory, while talking about VB compilation options, asks “what exactly can one expect to gain by enabling optimizations?” It’s a good question, and one that the docs are kind of vauge about. Turning on optimizations, which is the default for release builds, does three major things at the compiler level:

  • It removes any NOP instructions that we would otherwise emit to assist in debugging. When optimizations are off (and debugging information is turned on), the compiler will emit NOP instructions for lines that don’t have any actual IL associated with them but which you might want to put a breakpoint on. The most common example of something like this would be the “End If“ of an “If” statement – there’s no actual IL emitted for an End If, so we don’t emit a NOP the debugger won’t let you set a breakpoint on it. Turning on optimizations forces the compiler not to emit the NOPs.
  • We do a simple basic block analysis of the generated IL to remove any dead code blocks. That is, we break apart each method into blocks of IL separated by branch instructions. By doing a quick analysis of how the blocks interrelate, we can identify any blocks that have no branches into them. Thus, we can figure out code blocks that will never be executed and can be omitted, making the assembly slightly smaller. We also do some minor branch optimizations at this point as well – for example, if you GoTo another GoTo statement, we just optimize the first GoTo to jump to the second GoTo’s target.
  • We emit a DebuggableAttribute with IsJITOptimizerDisabled set to False. Basically, this allows the run-time JIT to optimize the code how it sees fit, including reordering and inlining code. This will produce more efficient and smaller code, but it means that trying to debug the code can be very challenging (as anyone who’s tried it will tell you). The actual list of what the JIT optimizations are is something that I don’t know – maybe someone like Chris Brumme will chime in at some point on this.

The long and the short of it is that the optimization switch enables optimizations that might make setting breakpoints and stepping through your code harder. They’re all low-level optimizations, so they’re really applicable to pretty much every kind of application in existence. They’re all also very incremental optimizations, which means that the benefit of any one optimization is likely to be nearly unmeasurable except in the most degenerate cases but in aggregate can be quite significant. I definitely recommend everyone leave this option on for your release build…

Biculturalism, VB and C#

One more thing that might not really last the month until I get back, so I’ll get it out now… One of the recurring questions/debates that goes around the web is “why have two languages (i.e. VB and C#) when one would do?” This is a question that begs an involved discussion but I think Joel Spolsky’s discussion of the separate cultures of Unix and Windows provides an excellent starting place. Replace “Unix” with “C/C++/C#/Java” and “Windows” with “VB” and I think he starts to capture the essence of the reasons why VB exists.

Maybe in February I can elaborate on my thoughts on this, although I’m not sure I can explain it better than Joel does. I thought this particularly captures my feelings in response to people who say that “C# and VB are the same language with slightly different syntax”:

What’s left is cultural differences. Yes, we all eat food, but over there, they eat raw fish with rice using wood sticks, while over here, we eat slabs of ground cow on bread with our hands. A cultural difference doesn’t mean that American stomachs can’t digest sushi or that Japanese stomachs can’t digest Big Macs, and it doesn’t mean that there aren’t lots of Americans who eat sushi or Japanese who eat burgers, but it does mean that Americans getting off the plane for the first time in Tokyo are confronted with an overwhelming feeling that this place is strange, dammit, and no amount of philosophizing about how underneath we’re all the same, we all love and work and sing and die will overcome the fact that Americans and Japanese can never really get comfortable with each others’ toilet arrangements.

Couldn’t have said it better myself…

A plug for “Code Generation in .NET”

I just wanted to put in a quick plug for Code Generation in .NET, Kathleen Dollard’s new book. Besides being an author, Kathleen’s also a passionate VB user and we’ve had many discussions over the years about the design and progress of the language. She’s also incredibly passionate about code generation and given some of the detailed emails that she’s sent me on the subject, this book can’t help but be great. If you’re doing code generation in .NET, I’m sure this is going to be the book to buy.

Default arguments are not perfect

My previous entry on default arguments raised a few questions. I thought it’d be worth writing another short entry to make a few things clearer.

The first thing is that default arguments could certainly have been implemented by overloads under the covers or in some other way that was version resillient. However, the CLR supports default arguments natively because: a) they were already a fundamental part of C++ and VB and b) they were already a fundamental part of COM. Rather than imposing a lot of overhead on the interop layer and the two languages, it seemed best to just implement default arguments as default arguments (especially since they’re only a tiny bit of extra metadata as far as the CLR is concerned). And, as I said in my first entry, not everyone agrees on the seriousness of the versioning question in the first place.

James Slaughter is right in that default arguments certainly introduce some interesting dilemmas for languages that support overriding and delegates. We had to work through those questions in the VS 2002 timeframe, but by taking a pretty conservative stand (I believe we just require you to restate the defaults exactly), I think it ends up being pretty clear and usable. I’m not sure how C++ approaches the problem, though.

Brad asks (more or less) “If all languages supported default arguments, then when would you use one over the other?” I think the answer, like so many class library questions, boils down to questions of aesthetics which are never easy to quantify. As I touched on in my original entry, I think in most cases overloads make a lot of sense. But there are some places where default arguments can make more sense. The best example I can think of is a Print method that optionally prints a newline. The BCL deals with this issue by creating two names, Print and PrintLine:

Sub Print(ByVal Value As Object)
Sub PrintLine(ByVal Value As Object)

This is an entirely valid way to deal with the situation. But in practice, you could also use default arguments to elegantly finesse the situation:

Sub Print(ByVal Value As Object, Optional ByVal NewLine As Boolean = True)

I’ve found myself doing this in the past when working on the compiler because it’s an easy way to extend a well-established method without having to create a whole new name.

Anyway, the point isn’t so much that default arguments are perfect, just that they can be useful in situations. I think one could come up with good design guidelines to allow choosing between the two, and maybe someday I’ll sit down and try to dream them up. Until then, we’ll all just have to muddle along…

Why not ++ and –?

One question we occasionally get is why we didn’t introduce C-style increment (++) and decrement (–) operators into the language when we introduced the compound operators (i.e. += and -=). We did consider it, but:

  1. Assignment in VB is always done at the statement level and not the expression level. Introducing a ++ statement and — statement seemed pretty redundant. If you’re going to have “x++” as a statement, why not just use “x += 1”?
  2. If we introduced ++ and — as assignment expressions, then it would be weird not to allow general assignment expressions. For example, in C#, you can say “if ((x = foo()) == 10) {}” and have the assignment done as part of evaluating the if expression. The problem, as you might have already guessed, is that we already use the = operator in expressions for testing value equality. Thus, there would be no easy way to introduce general assignment expressions into the language, which would make it strange that we had — and ++.
  3. Even if we ignored the weirdnesses inherent in having increment and decrement with no assignment, the operators’ main function in C often times seems to be to encourage programmers to write arcane and brittle code. Besides the confusion in meaning between prefix and postfix, the increment/decrement operators usually depend on the order of evaluation of expressions. Which requires remembering the order of evaluation in a particular language, which isn’t always very obvious. For example, in C, what do the following expressions result in? It really depends on the order in which the expressions happen to be evaluated.
a[b++] = b
a[b] = ++b
foo(b++, ++b, b++, ++b)

Overall, we felt we were better off just leaving the increment and decrement operators alone.

Default arguments are bad? I don’t buy it.

Although I greatly respect the opinons of my fellow Microsoft employees (and most other people, for that matter), there are times when we have honest differences of opinions. A recent blog entry by Brad on default parameters is a good example.

I understand the versioning argument that he and the C# team make about default arguments, but I just don’t buy it. I think that not having (or not ever using) default arguments because of versioning is throwing out the baby with the bathwater. Brad gives an example of a VB function with a default argument:

Function ComputeTotal(ByVal subTotal As Double, Optional ByVal salesTax As Double = 8.8) As Double
Return subTotal + subTotal * salesTax / 100
End Function

He suggests that the following would be better:

Function ComputeTotal(ByVal subTotal As Double, ByVal salesTax As Double) As Double
Return subTotal + subTotal * salesTax / 100
End Function

Function ComputeTotal(ByVal subTotal As Double) As Double
Return ComputeTotal(subTotal, 8.8)
End Function

He feels the latter example is better because you can change the default value of salesTax and automatically have all clients compiled against the method pick up the change. Which is true. But I have to ask: what class library designer in their right mind would change the default value in the first place?

One of the major areas of concern for class library designers inside of Microsoft is compatibility, and one of the cardinal rules of compatibility is that you don’t make this kind of behavioral change. Why not? Because you’re likely to break people who depend, rightly or wrongly, on the default behavior that you introduced. (If you have any doubts about this, go talk to Raymond.)

In the given example, yes, the state may have changed its sales tax and so the calculation function may need to change. But just changing the default may cause serious issues. What if your application needs to calculate sales tax for sales that occured before the sales tax rate changed? Yes, you should have explicitly stated the sales tax you want to use, but it’s just as likely you used the default because: a) it’s easier and b) at the time you wrote your code, you got the expected result. As a result, when the default changes you’ll end up willy-nilly calculating the sales tax with the wrong rate! I would argue that in this situation the problem has less to do with default arguments or overloading than it does with bad API design.

My point is that whether you use default arguments or overloading, it’s extremely unlikely that you’re ever going to be able to change default values once you’ve published an API. That is, unless the API is completely internal to your application. In which case, the versioning “problem” with default arguments doesn’t apply! So in this case, I think the prohibition against default arguments is worrying about what happens in a situation that shouldn’t occur in the first place.

I will hasten to add that this doesn’t mean that I don’t think that overloading isn’t a good thing or that default arguments can be abused. (Anyone with any doubt on that last point only has to look no further than the Office object model.) In practice, I think that proper API design trends in favor of overloading simply because it encourages simpler API calls and reduces the need for things like named arguments. But there are definitely places where default arguments can be used to avoid adding superfluous overloads with very little overhead.

Another interesting use of When

Ok, I think I may have done the “When” thing to death, but Sam Spencer, a PM who used to work on the compiler, pointed out another interesting use of it. Often times, applications will have a global exception handler in the Main method that catches any exceptions that weren’t handled elsewhere. Something like:

Sub Main()
Try
RunApplication()
Catch ex As Exception
HandleGlobalException(ex)
End Try
End Sub

The compiler itself uses a strategy similar to this for out of memory situations — once we’ve run out of memory, the compiler’s toast, so we throw an exception indicating “out of memory” and then catch it at the top level, giving a nice “out of memory, please restart the compiler” error. (Hopefully none of you have ever seen it.)

Anyway, when you’re debugging the application it can be convenient to not catch exceptions at the top level so that you immediately break into the debugger when you get a global exception. A simple way to do this is to use When to not catch the exception when a debugger is present:

Sub Main()
Try
RunApplication()
Catch ex As Exception When Not System.Diagnostics.Debugger.IsAttached
HandleGlobalException(ex)
End Try
End Sub

Kind of cute.