Fabulous Adventures In Coding
Eric Lippert is a principal developer on the C# compiler team. Learn more about Eric.
Oddly enough, my posting on how to handle a mad crush has become the third most popular article I've written so far. Who knew there were so many 10 year old girls interested in programming language design? I may have to turn this into an agony column. I've posted some more techniques for handling a mad crush, for the benefit of all you 10 year old girls reading my blog.
In other news, I was going through my email archive the other day and I found a discussion from back in the days when we were designing the VB.NET syntax that I thought might give some insight into the kinds of considerations that go into some of the smaller decisions.
A lot of people have opined that VB.NET and C# are in many ways the "same language", just with different syntax. If you were to take a chess board and change it from black and white to red and blue and you renamed all the pieces, but didn't change the more fundamental rules about the ways the pieces moved, the new game would in a very real sense be "the same game as chess," right? Whether VB.NET and C# really are in that sense mere syntactic variations on each other is a debatable point -- I think it is not nearly so cut-and-dried as some people think. There are a lot of reasons I think that, and I don't want to go into all of them today. One of the most interesting and important to me though is the most ineffable -- the "spirit" of a language in many ways both transcends its syntax and suffuses some small decisions in interesting ways.
Let's consider just one small example. VB6 did not have the
x = x + 10
Looking at that, there's some textual redundancy there. Clearly the intention of the programmer is "increment the variable by ten", so why do we have to state the variable twice? This is an extremely common, simple operation so we can have a short-cut syntax for it that expresses it more compactly. (Such a shortcut, whereby a relatively cumbersome but legal syntax is replaced by a simpler syntax that adds no additional real representational power to the language is called a syntactic sugar.)
x += 10
And indeed,
Since incrementing a variable by one is also an extremely common operation, C-like languages have an even more compact syntactic sugar for this operation:
When the decision was made to add the
I am pleased to see the
Actually, it isn't as natural as you might think, because VB.NET and C# are NOT mere syntactic variations on each other, and nor should they be. The reason why VB.NET doesn't have the increment operator illustrates the difference in spirit between VB.NET and C#. In fact, it is NOT the case that a C-like
{ 2 + 2; }
Not a particularly useful fragment, one that would probably produce a compiler warning, but legal -- because in C, a bare expression with no side effects is a legal statement.
In C it is also legal to go to the other end of the spectrum and say
x = (k += 1);
k += 1
That's not the case in VB.NET. In VB
But
x = (k++) * (++k);
And get both the side effects (two increments), the multiplication and the assignment to
If you make the increment operator only legal in statements
But if you make it a legal expression in VB.NET, you run into all kinds of problems. This operator causes problems in C-like languages, and it would cause the same problems in VB.NET.
Consider a hypothetical world in which
Function Foo(ByRef x, ByVal y) Foo = x * y x = 10End Function
k = 100z = Foo(k++, ++k)
First of all, what numbers get passed to
z = Foo(100, 101)
or this?
z = Foo(100, 102)
z = Foo(101, 101)
Second, does the
Stick
or this:
Or, if it passes by value then
We could come up with some answers to these questions, but they would be rather arbitrary. The answers are apparently sufficiently inobvious that the C++ standard leaves several of them unanswered, and therefore such code is not portable! The question about function parameter list evaluation order is dismissed as
Clearly these problems are solvable -- we solved them in C#, obviously! -- but you have to ask yourself how valuable saving that keystroke is if it adds these kinds of complexities to the language semantics. Adding complexity isn't necessarily bad, but you should get value for your additional complexity, not a single keystroke saved!
k++
I'm all for adding syntactic sugar that makes code less verbose.