"Regarding the C# decision that the default should be non-virtual rather than virtual, I can't put words in the designer's mind. I can tell you exactly why it's the default in C++."
I certainly can't put words in the C# designer's mind. But I do believe this feature is an improvement over Java.
The reason for this is that it is very difficult to design a class for extension. What is safe for a subclasser to override? If a method in a class wasn't designed to be overridden, then there is a good chance that there will be undesirable behavior. See Joshua Bloch's item #15 in
Effective Java.
I remember hearing that the original implementation of java.util.Hashtable allowed overriding of put(key, value), and there was some vague complication because it was never designed to be overridden. For example, you might try to override it by saying:
if (!somecondition)
super.put(key, value);
However, the original java.util.Hashtable implementation did something like this pseudocode:
if (get existing entry)
update existing entry and return the old value
if (adding)
{
increment count
if (count > threshold)
{
rehash()
put(key, value)
}
}
create new entry
Notice that this would result in "put" on the inheriting class being called twice on occasion of needing to rehash (ie, unpredictably from the using application's point of view).