A Conversation with Anders Hejlsberg, Part IV
by Bill Venners with Bruce Eckel
September 15, 2003
Anders Hejlsberg, the lead C# architect, talks with Bruce Eckel and Bill Venners about why C# instance methods are non-virtual by default and why programmers must explicitly indicate an override.
- In Part I: The C# Design Process, Hejlsberg discusses the process used by the team that designed C#, and the relative merits of usability studies and good taste in language design.
- In Part II: The Trouble with Checked Exceptions, Hejlsberg discusses versionability and scalability issues with checked exceptions.
- In Part III: Delegates, Components, and Simplexity, Hejlsberg discusses delegates and C#'s first class treatment of component concepts.
- In this fourth installment, Hejlsberg explains why C# instance methods are non-virtual by default and why programmers must explicitly indicate an override.
Non-Virtual is the Default
Virtual Has Two MeaningsAnders Hejlsberg: When you say "virtual," you can mean one of two things. If you did not inherit a method of the same signature, then this is a new virtual method. That's one meaning. Otherwise it is an override of an inherited method. That's the other meaning.
From a versioning perspective, it is important that the programmer indicate their intent when they declare a method virtual. In C#, for example, you must explicitly indicate which meaning of virtual you intend. To declare a new virtual method, you just mark it
virtual. But to override an existing virtual method, you must say
As a result, C# doesn't have the particular versioning problem I described earlier in which we introduce a method in a base class that you already have in a derived class. In your class, you would have declared
foovirtual. Now we introduce a new virtual
foo. Well, that's fine. Now there are two virtual
foos. There are two VTBL slots. The derived
foohides the base
foo, but that's fine. The base
foowasn't even there when the derived
foowas written, so it's not like there's anything wrong with hiding this new functionality. And things continue to work the way they're supposed to.
Bruce Eckel: So you saw this versioning problem happen often enough in practice, that you decided to address it? I remember you did a similar thing in Delphi.
Anders Hejlsberg: Yes.
Bruce Eckel: You're perspective on languages is quite different from the other people that I've talked to. It's very pragmatic.
Anders Hejlsberg: I have always described myself as a pragmatic guy. It's funny, because versioning ended up being one of the pillars of our language design. It shows up in how you override virtual methods in C#. Also, the way we do overload resolution in C# is different from any other language I know of, for reasons of versioning. Whenever we looked at designing a particular feature, we would always cross check with versioning. We would ask, "How does versioning change this? How does this function from a versioning perspective?" It turns out that most language design before has given very little thought to that.
Bruce Eckel: Were you concerned about versioning primarily because of the DLL hell problem?
Anders Hejlsberg: Yes, but also because of changes I've observed over the years. Ten to fifteen years ago, back when we had the 640K barrier, heck, you could just throw all your code away every year and rewrite it. The rewrite took about a year, and that coincided with the next release. So you didn't really have to worry about reusing the old stuff. Versioning? What's that? We started from scratch every time.
I hate to break it to you, but that's gone. We will never catch up. We will never fill all the capacity that Moore's law is heaping on us. The way we get more functionality these days is by doing more and more leveraging of existing infrastructure and existing applications. As systems are becoming longer lived, versioning is becoming more important.