When I switched over the C# compiler team, I had hoped that I would be able to give some insight into how the design team works, what decisions we make, etc. Language design is a very esoteric field, and there’s not a lot written about it (though “Design and evolution of C++“ is a pretty good read). I had hoped that I would be able to do this with concrete examples, as that makes it much easier.
I’ve been watching for candidate topics to write about, but haven’t yet come up with any good ones. One of the problems is that features have a tendency to morph in design (and in whether they’ll make it into Whidbey) as time goes by, and it would be bad for me to say, “we’re talking about doing<x>“ and then have us decide it wasn’t a good idea. Or, for us to decide that <x> doesn’t fit into our schedule, or it would break existing code, or any of the other reasons that might cause us to pull a feature. We’re generally not comfortable really talking about those things until the feature is in somebody’s hands.
In lieu of such an example, I’ve decided to write something a bit more abstract about how we look at things.
I’ve been spending a lot of time answering customer questions about why we do (or don’t) have certain language features in C#. (as an aside, yes, we will be getting more of this online on the C# dev center).
In some of those questions, the questions asks why we either “took out” or “left out” a specific feature. That wording implies that we started with an existing language (C++ and Java are the popular choices here), and then started removing features until we got to a point where we liked. And, though it may be hard for some to believe, that’s not how the language got designed.
One of the big reasons we didn’t do this is that it’s really hard to remove complexity when you take a subtractive approach, as removing a feature in one area may not allow you to revisit low-level design decisions, nor will it allow you to remove complexity elsewhere, in places where it support the now-removed feature.
So, we decided on the additive approach instead, and worked hard to keep the complexity down. One way to do that is through the concept of “minus 100 points”. Every feature starts out in the hole by 100 points, which means that it has to have a significant net positive effect on the overall package for it to make it into the language. Some features are okay features for a language to have, they just aren’t quite good enough to make it into the language.
A feature like expression filters in VB is in this bucket. Yes, being able to put a condition on a catch is somewhat more convenient than having to write the test yourself, but it doesn’t really enable you to do anything new.
Being able to have property accessors with different accessibilities was another example of this. We had some experience with users being able to specify different levels of virtual-ness (virtuality?) on different accessors in an early version of the language, and it was a really confusing feature, so we elected to remove it. We felt similarly about differing accessibilities, and so we left it out of the 2002/2003 versions of the language, but we got *so much* feedback from customers that we re-evaluated the utility of the feature, and decided to add it to the language in the Whidbey version.
One can argue that we should perhaps have come to that conclusion earlier, but I don’t think that being cautious is a bad thing when doing language design. Once you add a feature, it’s in the language forever.
I should also probably note that this isn’t the only reason features don’t make it into the language. Some features provide enough utility in the abstract, but when we go to come up with a workable design for the feature, we find that we can’t come up with a way to make it simple and understandable for the user. That means that in some cases we like a feature in the abstract, but it’s not in the language.
There is also another class – features that we don’t want to get near the language. But that would be another post.