Author Archives: paulvick

Why internal blogs don’t make it

Scoble wrote yesterday about the fact that even though there are a growing number of MS people with external blogs (enough to force the move off of GDN), there hasn’t been a commensurate number of internal blogs. In fact, I’d have to say that pretty much most of the internal blogs that I’ve read are a dismal failure, and I’ve dropped every single one out of NewsGator. Robert speculates that the problem has to do with discoverability and linking, but I think the problem goes deeper than that. Specifically, I don’t think internal blogs work very well because:

  1. External blogs make Microsoft people be more open and less insular in the way that they talk about things. Public blogs expose our thoughts to a pretty broad range of people, so we have to assume less and explain more. Internal blogs, on the other hand, allow us to make lots of assumptions about shared knowledge, meaning that internal blogs tend to be more dry and less interesting. Which, in turn, makes them less fun to write.
  2. External blogs expose us to people who don’t agree with what we have to say, to put it mildly. This provokes lively debate and interesting discussions in a way that is harder to replicate internally. I’m not saying we’re the Borg here, but there is a shared culture within the company that makes people a bit more decorous. Decorum also makes people, I think, less likely to rock the boat on internal blogs. This doesn’t make much sense since people inside the company read external MS blogs too, but there you are.
  3. It’s like the old Friends joke where the gynecologist says about his work, “It’s like being a waitress. When you get home, the last thing you want to do is look at another cup of coffee.“ Most of us spend our days talking to and emailing other Microsoft employees. The last thing we want to do is write the equivalent of another memo. It’s much more fun to talk to outside people.
  4. One of the big things that external MS blogs provide is information about what MS is doing. Internally, there are a lot of resources available to employees that often trump blogs. (Not that there isn’t room for improvement, as Scoble notes.) I don’t read Chris Brumme’s or Suzanne Cooke’s excellent blogs anymore because a good amount of the information they talk about is available in internal specifications. And if there’s something piece of information I can’t find, I have the luxury of calling them up or scheduling a meeting with them to get my questions answered.

I’m pretty skeptical whether internal blogs really will ever work. I’m more intrigued as to whether collaborative technologies like wikis can make a big difference. After I get back from some major vacation (more on that later), it’s something I’d like to explore inside of the VB team.

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.

It’s good to know we are not alone…

Stan Lippman, a C++ guru at Microsoft has started blogging. His inaugural entry discusses one of the issues that their language design team faces in moving C++ to the CLR. Near the end, in a section entitled “The C++.NET Design Challenge,“ he says:

Literally, for every aspect of the C++ extensions to support .NET the question always reduces to “How do we integrate this (or that) aspect of the Common Language Runtime (CLR) into C++ so that it (a) feels natural to the C++ programmer, and (b) is easy to use in its own right under .NET. I like to call this the Janus face dilemma. (Janus is a two-faced Roman diety, the one turned facing towards what has just been, the other towards what is to be.)

As my entry title says, it’s good to know that we (the VB team) are not alone. Moving VB to the CLR was a major undertaking involving many, many, many dilemmas along these lines. Even though C++ and VB are two very different languages, I have a lot of empathy for what the C++ team is going through as they struggle with these questions. It’s not an easy path to trod.

Publishing lag

One comment I’ve gotten several times over from family members this Thanksgiving is “I was at the bookstore and I looked for your book, but it wasn’t there.” Apparently, in all my grousing about getting the manuscript in, I gave the impression that as soon as I turned in my manuscript, the book would go out to the shelves. I’ve still got all the grunt work of reviewing copy edits and page proofs to go before I get something real in my hand.

The book’s going to be part of the Microsoft .NET Development Series published by Addison Wesley that John Montgomery’s been talking about. The series includes books by Don Box and Chris Sells, which is a bit scary company to be keeping. On the other hand, I made a small contribution to one of the books in the series already, and they haven’t laughed me out of the club yet…

Gobble gobble gobble

It should come as no suprise to anyone, but entries this week are going to be slow given that I am visiting family for Thanksgiving. The feed, at least, is fixed thanks to a prod by Darrell Norton. I’ve had a lot of problems with FreeTextBox not translating my particular style of writing into valid XHTML, so my feed keeps getting broken by me incorrectly fixing up the HTML. Anyway, when I get back and get some time, I’ll look into solutions, but for now…

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.