Virtual by default or not?


I’ve been skimming through “Hardcore Java”, and I came across a section on the use of ‘final’ in Java. In it, one of Simmons’ comments (okay, I’m not sure it’s his comment because he’s listed as editor and not author, but that sounds better than “whoever wrote this section) is (and I’m paraphrasing here):


Don’t use final on methods unless you’re sure you want them to be final


He then goes on to say that this is because you never know who might want to extend your class.


There are really two viewpoints on this issue. They are:


“Make it virtual in case somebody wants to extend it”


and


“Don’t make it virtual unless you’re sure somebody wants to extend it”


I’d like to expand on the first viewpoint, which I’ve sometimes labelled as “speculative virtuality”. I don’t like it.


My reasons have everything to do with predictability and robustness. If you can’t conceive of a user extending your class in a specific way but still choose to provide such extensibility, then it’s pretty clear that you don’t have an extension scenario in mind, which means that neither your code nor your tests are likely to ensure that it does work – especially across versions. Sure, it’s possible that it may work in the current version, and may even continue to work in future versions, but I wouldn’t call it a supported scenario. I’d prefer to use classes where I know what I’m doing is supported.


The second issue is around understandability. If I walk up to a class (in the metaphorical sense, of course, you can’t really “walk up” to a class) and it has 29 virtual methods, it’s hard for me to tell whether the author *intended* me to extend the class through a certain method or set of methods, or whether they just left them virtual “just in case”. Where if a class only has one (or a small number) of virtual methods, that’s a good indication that the designer wants me to use them (ie they’re part of a supported scenario).

Comments (29)

  1. Matt Minyard says:

    Regarding "Speculative Virtuality" Josh Bloch doesn’t seem to like it either in "Effective Java." Specifically #15: "Design and document for inheritance or else prohibit it" It was also mentioned in an interview at http://artima.com/intv/blochP.html

    Matt

  2. As a counterpoint, there are many times I’ll walk up to a class and find out that it does everything I want but one method is incorrectly implemented (or just not implemented in the way I need).

    Often in that case, I can look at the source using Reflector and carefully override that one method. Unless it’s not virtual. The ideal solution would be to have the author fix the problem, but that’s not always done in a reasonable timescale.

  3. Jerry Pisk says:

    So it comes down to control. Eric seems to be inclined to dictating the end user what they’re allowed to do and what not. As oposed to opening up and letting the user do whatever they want, including shooting themselves in the foot (which I prefer, because most of the time you have really no idea who your end users are going to be and what their needs are).

  4. Joe Duffy says:

    I think this viewpoint is probably caused by a fairly large cultural difference between Java (especially earlier on) and .NET. Since in Java "everything is virtual" by default, this Java design decision is often taken for granted and not questioned by native developers. Josh Bloch’s and other publications took a great step toward changing this mentality, and in general the Java community has really gone in the direction of composition and interface/delegation instead of inheritance for everything. However, there still exists quite a strong feeling that every type should remain open to what you refer to as "speculative virtuality."

    Coming from a Java background, I was stunned and perplexed when I first learned it was necessary to opt-in to being virtual in C#. Almost heresy, in fact. Why? Not because I thought inheritance was the extensibility panacea, but rather because I was in the habit of saying when I didn’t want virtuality versus saying when I did. It sounds like a pretty minor difference, but it’s actually very fundamental and hardwired into the platform developer’s thinking.

    I still haven’t made up my mind entirely about this one (similar to checked exceptions), but I do see convincing arguments both ways.

  5. Drew Marsh says:

    I totally agree with you, but allow me to play Devil’s advocate and ask: Why then are C# classes not "sealed" by default? In other words the "sealed" keyword should really be "extensible" and you should have to explicitly choose for your class to be a base class just like you should choose which methods should be virtual. 🙂

  6. Leo von Wyss says:

    Sure enough, your idea that as little as possible should be virtual has been well applied in large areas of the .net framework.

    Unfortenately, this often makes it quite hard to do some things you’d want to do. This is especially true for rather "generic" areas like the asp.net infrastructure that could be used to do very many cool things the guys in charge at MS probably did not think about (talking about multiple-language pages, for instance), if only you could get a little more control.

    If many cases, you have to go and re-do quite a bit of infrastructure (thanks to Reflector for help on this…) because you want to customize one little thing…

    So maybe it should be ‘virtual only if it makes sense’, but in a somewhat more generous way?

  7. SimonT says:

    I quite the Java route liked because I wasnt relying on the muppets to remember to virtual something.

    But then on the flip side, would I want to use the muppet developed class.

  8. Thomas Eyde says:

    This assumes you know every future needs of your clients. As far as I know, nobody has achieved that.

    Even if there are many virtual methods, should I override them just because I can?

    I have posted this question numerous times and are still waiting for a good answer: How do I design for extention when I don’t know how my future client will use my class?

    The User Interface Application Block is a good example where classes are closed for extention when they shouldn’t. Classes are sealed or internal, methods which should be virtual are not. This means that the only way I can adjust the framework to my needs is to edit the source code. I don’t want to do that, because my changes will never survice the next framework release.

  9. I agree with the Thomas – you assume to much knowledge on the part of library designers. This kind of thing makes the life of application developers hell. See my full response here:

    http://www.cincomsmalltalk.com/blog/blogView?showComments=true&entry=3262321958

  10. John says:

    I like what Kelvin Henney [1] has to say, "design considered useful" and "Reuse has proven to be a false idol to worship".

    A class is designed to do a thing. If it is *designed* to be extended then you’d use vitual methods (and template methods, etc.) thoughtfully. Otherwise, it’s not designed to be extended, in which case marking something as virtual is a bad idea.

    I entirely agree that the default is ‘final’. Most classes are not designed to be extended, and designing classes to be extended is a difficult thing to do well. Software development is about managing complexity, and virtual methods don’t help me do that.

    John.

    [1] http://www.two-sdg.demon.co.uk/curbralan/papers/minimalism/TheImperialClothingCrisis.html

  11. Thomas Eyde says:

    So how, exactly, do you design something to be extendable? How do you know when something is not extendable? Just because you don’t need to override something doesn’t mean I don’t. I can take your class and see usages you never thought of. Who are you to tell me that my prefered implementation is flawed? I know what I need, you don’t. I can use Reflector to inspect your code and see it is perfectly safe to override, even if you made the method inaccessible.

    Just because you can’t see the need to override doesn’t mean it is unsafe to do so.

  12. John says:

    > So how, exactly, do you design something to be extendable? <

    There are a few ways, the most common is to use template methods and virtual methods. You need to program by contract, and anyone who extends your class needs to understand their responsibilities when they override one of your virtual methods, that’s why patterns are useful.

    > Who are you to tell me that my prefered implementation is flawed? <

    If I designed the class, then I am the guy to tell you your ‘prefered implementation’ is flawed.

    A class that I create was designed for a purpose. It is used for that purpose, and that’s all. If the class can’t be extended in the way that you want, then maybe you’re using the wrong class, trying to do something you shouldn’t, or my class sucks (ala WinForms). None of these are good reasons to make methods virtual by default, virtual methods should be the exception. I also think classes should be sealed by default too. It’s the principle of least privelege.

    > I can use Reflector to inspect your code and see it is perfectly safe to override, even if you made the method inaccessible. <

    Don’t be a moron. Think about what you are saying. Clearly this is ‘hacking’, not ‘software engineering’.

    John.

  13. Thomas Eyde says:

    "Don’t be a moron. Think about what you are saying. Clearly this is ‘hacking’, not ‘software engineering’."

    No. It’s inspection to see what’s really going on. This way I can learn more about your implementation and see what’s safe and what’s not.

    I also design my classes for a purpose. But in contrast to you, I think it’s wonderful when someone find a usage scenario I didn’t think of.

    We have also seen examples of when a class should be open for extention but is not. Isn’t that an oo principle: Closed for modification, but open for extension?

    I am glad we don’t have it completely your way, then most would be closed for anything.

    Funny, this. Before .Net everybody argued how bad VB6 was, no inheritance and all. Now the argument is how bad oo is, and how we should be protected from ourselves.

  14. John says:

    > No. It’s inspection to see what’s really going on. This way I can learn more about your implementation and see what’s safe and what’s not. <

    You shouldn’t program to my implementation, you should program to my interface.

    This is a remarkably dodgy way to design software by the way. Yes, it helps in your understanding and learning to see what is really going on in an implementation, but you shouldn’t rely on it. I don’t trust someone who thinks this is a valid way to program not to make a horrible mistake thinking that something is safe when it is not.

    > But in contrast to you, I think it’s wonderful when someone find a usage scenario I didn’t think of. <

    Using a class is different to extending it. Also, people can extend my class to do things I hadn’t considered, but only within the bounds that I’ve allowed them to. A base class is not a second-rate citizen, it’s a crucial building block, and it ought to be solid.

    > I am glad we don’t have it completely your way, then most would be closed for anything. <

    This is not true. I’m all for extensible framework APIs. My point is that most user code is not framework code, it’s application code designed to do a specific thing. This code is final, sealed, etc. If it needs to change then you create a new version, not a derived class.

    If you are creating framework APIs you do so explicitly. So, virtual by default is a very bad idea, because you didn’t necessarily think about what it was that you were doing.

    I wouldn’t trust someone who had the ‘virtual by default’ mentality to design robust frameworks. The syntax isn’t so crucial, as the mentality, but I think the syntax requiring an explicit ‘virtual’ decoration is a good idea.

    John.

  15. Val Savvateev says:

    Ditto to every line in this post.

  16. Well not to mention the fact that virtual methods can’t be inlined. 🙂

  17. Staffan Gustafsson says:

    Virtual methods can be inlined if you can prove the "Single Subclass assumption". (The optimization has to be reversed if a class is loaded that changes that assumpiton), or you can make a guarded inline if the vast majority of the calls are going to one or a few distinct classes.

    Most JVM’s today do that, (probably necessary because of the "virtual by default" language choise.)

    In general, I find the CLR (v1.1 at least) to be lacking in inlining cababillities, and it also produce less efficient code than for example the JRockit JVM.

  18. Thong Nguyen says:

    <i>My reasons have everything to do with predictability and robustness. If you can’t conceive of a user extending your class in a specific way but still choose to provide such extensibility, then it’s pretty clear that you don’t have an extension scenario in mind, which means that neither your code nor your tests are likely to ensure that it does work – especially across versions

    </i>

    Even if you can’t imagine a situation where you would want to override, it’s still possible to write your code in such a way that the virtual methods (which by their nature are public) are sufficiently black boxed that an overriden version won’t be a problem. Just because you find it hard to imagine a use for overriding a method doesn’t mean that me or other users of your class can’t.

    I’l like to see your response to why C# doesn’t have classes "sealed" by default or why most classes in the .NET BCL aren’t sealed.

  19. Alex says:

    My 2 cents on the Sealed by default argument.

    They appear similar in concept but to me its about making your intentions as a class designer clear: what your saying when you declare a virtual? and compare that to the statement your making when you declare a class sealed.

    By declaring a virtual you are stating a granular level of behaviour in a very specific way. This is different to what you state when using the same concept at class level.

    If you could declare a class ‘extensible’ you could be implying that the class as a whole is implicitly overridable – which clearly isn’t the case in C# (this of course is different to Java). Furthermore you are stating your extensibility level twice (if method A is virtual then the class X must also be extensible).

    By having a class explicitly declared as sealed you imply that the class is a final implementation and cannot be extended (which is true). You aren’t doubling your extensibility declaration and your intentions are therefore made clear to the user of your class.

    That’s my understanding of the default behaviour.

  20. MBA says:

    Helpful For MBA Fans.

  21. Karl Seguin says:

    Few keywords are as simple yet amazingly powerful as virtual in C# (overridable in VB.NET). When you

  22. Few keywords are as simple yet amazingly powerful as virtual in C# (overridable in VB.NET). When you