Should I mark all methods virtual?
Asked Answered
D

8

76

In Java you can mark method as final to make it impossible to override.

In C# you have to mark method as virtual to make it possible to override.

Does it mean that in C# you should mark all methods virtual (except a few ones that you don't want to be overridden), since most likely you don't know in what way your class can be inherited?

Dysgenics answered 22/1, 2013 at 3:54 Comment(12)
I like to think that in C# if you're doing something that feels fastidious, you're doing it wrong.Pepita
The opposite is true: lots of Java gurus advise making all methods final by default.Madriene
Jon Skeet on Inheritance Tax although that was nearly seven years ago and opinions change.Chapeau
@KonradRudolph, citation/source please!Mythify
@Mythify If I had one handy I’d have posted it. However, Joshua Bloch has repeatedly advised this, and I’m pretty sure Effective Java mentions it somewhere.Madriene
@KonradRudolph, you mistake final fields w/ final methods.Mythify
@Mythify No, I definitely don’t. Final fields are completely unrelated.Madriene
@KonradRudolph, I understand you realize the difference between them. Yet, what Mr. Bloch advises is the use of 'final' fields. He advises for composition and static factories but not for final classes/methodsMythify
@Mythify Forget about final fields, I know that he talks about them. But I think he also talks about final methods in Effective Java. However, I may misremember this. I’m sure though that he mentioned it elsewhere then – maybe in one of his talks.Madriene
@Konrad, right. I had the book in front of me when I wrote the comments; practically there are no final methods there, even less final classes - ThreadLocal is shown final, while in reality it is not. Some are used to show that even final doesn't help immutability (notorious j.u.Date), some final are used as "awful candidate for default serialized form" - StringList and so on.No class in collection framework is final, either.Admittedly, I'm no great fan of his, I haven't followed his talks but unless you have a source for Java guru advocating "final methods by default" I'd not accept it.Mythify
@Mythify I’m surprised by your sentiment. Why would Java gurus in general not embrace this view? It’s certainly the prevailing sentiment among .NET programmers (if Eric below isn’t enough for you, search for Jon Skeet’s views on the matter), why should that differ for Java?Madriene
let us continue this discussion in chatMythify
F
145

In C# you have to mark method as virtual to make it possible to override. Does it mean that in C# you should mark all methods virtual (except a few ones that you don't want to be overridden), since most likely you don't know in what way your class can be inherited?

No. If the language designers thought that virtual should have been the default then it would have been the default.

Overridablility is a feature, and like all features it has costs. The costs of an overrideable method are considerable: there are big design, implementation and testing costs, particularly if there is any "sensitivity" to the class; virtual methods are ways of introducing untested third-party code into a system and that has a security impact.

If you don't know how you intend your class to be inherited then don't publish your class because you haven't finished designing it yet. Your extensibility model is definitely something you should know ahead of time; it should deeply influence your design and testing strategy.

I advocate that all classes be sealed and all methods be non-virtual until you have a real-world customer-focussed reason to unseal or to make a method virtual.

Basically your question is "I am ignorant of how my customers intend to consume my class; should I therefore make it arbitrarily extensible?" No; you should become knowledgable! You wouldn't ask "I don't know how my customers are going to use my class, so should I make all my properties read-write? And should I make all my methods read-write properties of delegate type so that my users can replace any method with their own implementation?" No, don't do any of those things until you have evidence that a user actually needs that capability! Spend your valuable time designing, testing and implementing features that users actually want and need, and do so from a position of knowledge.

Ferritin answered 22/1, 2013 at 4:7 Comment(37)
+100 for "all classes be sealed and all methods be non-virtual until you have a real-world customer-focussed reason to unseal or to make a method virtual."Pink
I agree with this answer, but I find it funny that you advocate that classes should be sealed by default, which they are not.Lashio
-1 as I don't really agree. I personnaly stick with the open/close principle. I don't know how my classes are going to be extended, so I make an educated guess. Later on, I can refine my choices, based on customer feedback. That way customer's not blocked, and we both can keep moving on.Vann
Other side of this is: take a lot of time to actually consider extensibility points when publishing an API. .NET Framework is very good in that regard in most places and extremely bad in others (e.g [msdn.microsoft.com/en-us/library/ee436108.aspx](SerialPort restricts supported Encodings to those definied in mscorlib.dll)).Marlinmarline
This theory is really sound, if, you want to be a bloody dictator that want's to pass all the costs of your mistakes onto your customer: I didn't thought of that, so you're out of luck, and you're not the typical customer I was expecting. It's a fine theory until you're at the other receiving end when you basically need something and you cant do it by simply adding some behavior, but instead you realize you need to do some of the stupidest workarounds out there. I agree about the security concerns, and those are valid, but doing this to save your ass and cut "your" support costs only is bad.Fearless
@PopCatalin Your assumption is that making more stuff virtual protects your customer. Actually, it exposes the customer to your mistakes more.Tini
@deworde, exposed or not the customer may be able to fix them given the chance. A closed system may prove to be allot more costly for the customer than an open one.This is something that my experience has shown me over and over again.Fearless
-1 I don't agree either. You shouldn't have to limit the extensibility of your software with all known use-cases of your classes. Sealed + non-virtual types inhibits testing and the extensibility of your types and any the software that uses your types. You can look at System.Web as one of the most friction-encumbered and untestable HTTP Stacks in modern use today, 10+ years on and we still aren't void of the concrete ASP.NET types and its non-substitutable impls. After several attempts at new Web Abstractions, MS themselves aren't able to share functionality between their different HTTP stacksArsenault
I think its probably very important to make the distinction in re: the 'appropriate' answer here betw. "fwks for others" and "code used by ppl w access to change the source later". Non-virtual and sealed in the .NET fwk (as an example) was used in places it never should have been and consumers of that fwk are still saddled w those 10+yr-old 'assumptions' about 'necessary' extensibility points. You CAN'T predict how ppl will want/need to extend your classes so while 'virt-by-default' may be too far the other way, sealed by default is an equally poor choice IMO.Sunflower
The reason why making classes in a public API extensible is fraught with danger is that the moment you do so you have to throw out all assumptions you made about invariants in your design. Every method you write has to fully validate your classes internal state because you can't know that the person who derived a new class from yours didn't screw something up (not deliberately; but just because they couldn't know everything you did when you designed it). This turns into lots of extra validation code because all of your formerly internal state has to be treated as unsanitized user input.Fascicule
Can't believe I disagree with Eric Lippert here, but I'm with @Arsenault and sbohlen on this one. As mentioned, ASP.NET is the perfect example of a Fx that is a royal PITA to test / extend properly because of poor design choices of making classes sealed / internal / non-interface based. If you're building libraries for internal consumption and you control all the consumers, then yes, it's not a big deal to change later and ship a new version. If you intend to keep backwards compat like ASP.NET has, then you have to get the testing / extensibility right from the jump.Broth
Totally agree w/ @sbohlen. It was years ago when I used to work w/ C#, yet I still recall being disgruntled on the amount of sealed classes and inability to extend/override but introduce wrappings instead.Mythify
@Arsenault System.Web is simply badly designed, but not for the reason that it’s sealed. If you design classes properly they are small enough (SRP!) to be composed and not in need of unforeseeable extension. If you make everything extensible you end up with a badly designed mess. You are simply misattributing the failure of this API. Incidentally, nothing in this answer says that your design shouldn’t be interface-based.Madriene
@Clement You are arguing for a naive, outdated version of the open/closed principle. Its modernised version is entirely compatible with sealed-by-default classes.Madriene
Ok all you people who like making everything virtual and unsealed: do you also make all properties writable? You don't know if that might be convenient for a user, so you should do it, right? Why does the argument for unsealing not also apply to any of a thousand other kinds of extensibility that you are not in the habit of supplying?Ferritin
@KonradRudolph the failure of System.Web is this exact culture and the proliferation of sealed concrete types that are closed to extension. We should never have been forced to bind against sealed concrete types as all code only works against that single implementation provided by the framework, i.e. ASP.NET. AFAIK no other popular web platform suffers from this, Java uses interfaces and dynamic language frameworks (by nature) don't have this problem.Arsenault
@mythz: The question is not "was the extensibility model of ASP well designed?", though that is an interesting question. The question is "is it a good idea to make all methods virtual?"Ferritin
@Arsenault You claim that System.Web’s sorry state is due to the fact that the classes are sealed, and that not having them sealed (and not changing anything else) would solve all those problems. That’s simply a baseless assertion, and as such, can be rejected. Other web framework pursue fundamentally different approaches. (Note, again, that I’m not talking about interfaces here at all.)Madriene
@EricLippert I was highlighting the consequences of this line of reasoning and using ASP.NET as an example. I don't think the consequences of having non-virtual (and sealed) by default is justified (given most alt langs don't enfoce it). The real problem in practice is not being able extend/override built-in/3rd-Party behavior. Like Java's checked-exceptions I think non-virtual is good in theory, but fails in practice.Arsenault
@KonradRudolph It solves exactly the problem of being able to substitute implementation and behavior. I fail to see the benefit of not being able to extend HttpContext,HttpRequest,etc (which should've been interfaces) - it's much harder to test and provide alternative implementations for. Not being able to share code built against different .NET frameworks (e.g. HttpListener) is a consequence of this. This forces Alt .NET fx's (like servicestack.net) having to implement HTTP wrappers (read:hacks) in order to allow for code-reuse.Arsenault
@Arsenault You share/reuse code by composition. You cannot meaningfully substitute implementation parts if the base class isn’t designed for that. It’s not enough to make methods virtual, you actively have to design the class with extensibility in mind. And the fact that you say that these classes “shouldn’t have interfaces” but should be virtual is bunk: if interfaces aren’t appropriate, then neither are virtual methods.Madriene
Eric Lippert discusses his viewpoint in more detail on his blog entry, Why Are So Many of The Framework Classes Sealed?Angwantibo
@KonradRudolph I said the classes should've been interfaces (not the opposite) so we aren't forced to bind to a sealed + concrete implementations. As you might be aware there is no possibility of composition with ASP.NET types, you're stuck with the concrete impls that's exposed on the surface area of the API. So whilst composition over inheritance should be preferred, it's not possible.Arsenault
Funny how the purely technical considerations that force Microsoft to not make many methods virtual (or not have other extensibility points) seem to come up a lot less on open source projects.Gladi
Eric, when I first saw so many sealed classes I thought Microsoft compiler did not do CHA, so the virtual method always resulted in virtual calls. That's it I believed it caused (partly) by performance considerations.Mythify
@psr, totally agree, the new trend of locking and sealing everything drove me away from MS stacks to open source stacks on a couple of occasions. I believe this trend will continue in the future ...Fearless
@KonradRudolph you can extend by using composition, but sometimes it doesn't really make sens, and you end up with a lot of proxy methods. I don't want everything to be opened, like "all properties public!", but I think an educated guess on which methods are virtuals and which are not is better than sealing everything until a customer asks for some "virtualness"Vann
composition (wrappers) won't work with classes which take concrete seald types as arguments. Not everyone wants to rewrite/wrap a whole framework to change a little detail.Entresol
@Firo: If a method takes a concrete sealed type as an argument that's because they don't want you to change the details of the semantics of the passed-in object. Designing, implementing and testing code that takes arguments that have crazy, unexpected behaviours is expensive. Taking a concrete sealed type as an argument lowers costs for everyone. And besides, what about strings? Those are a concrete sealed type. Do you think that every method that takes a string should have to deal with strings that, say, have a Length property different from the number of characters in them?Ferritin
The reason you make classes virtual and unsealed but not writable properties is that they cater to different use cases. This whole argument basically revolves around "who supports extended code" - Eric & Microsoft feel that it's the class designers (unless MSDN says otherwise), and the disagreements feel it's their own responsibility. The compromise would be that sealed is considered "advice" by the compiler, and can be overridden with a "/running-with-scissors" switch that prompts you to accept the corresponding EULA.Printable
-1 Derived classes implementation are the responsibility of the implementor, not on the original devlopers. In contrast, Java makes it easy to extends classes and it works great with the @Override annotation. In .Net, it's a lot of pain to always beg a closed source developer to change a non-virtual methods to a virtual virtual one. It NERVER happens.Sport
@formix: Do you recommend that all C# base classes have public fields of delegate type, so that the method can be replaced at will by any user? If not, why not? That mechanism is far more flexible than virtual overrides, which can only replace a method via subclassing. Why should someone who wants to change the behaviour of a class have to resort to subclassing?Ferritin
@EricLippert: I'm not sure of what you mean by "have public fields of delegate type". A link to some doc would be appreciated. But to mitigate my previous comment, I must say that when your application is not meant to be extended, it makes no sense to mark all methods as virtual (other than what you need for your implementation). On another hand, if you create an application that heavily relies on IoC (using Unity for example), marking all your interfaces method's implementations with virtual shall be mandatory!Sport
@formix: Instead of public virtual void Foo() { Bar(); } you could write public Action Foo = () => { Bar(); }. Now if a user of the class wishes x.Foo() to call Blah() they don't need to override the class; they just say x.Foo = ()=> { Blah(); }. Virtual methods are a mechanism for customizing a class through subclassing. If customization by users is the goal then why require them to use subclassing? That's a completely unnecessary added complication. My point is that people who say to make everything virtual for maximum flexibility are hitting a point nowhere near the maximum.Ferritin
@EricLippert: Ok, got it. But I must admit that I find what you explain a bit alien (it looks like Javascipt done that way). I still believe subclassing should stay the mainstream way and I disagree with you that using good old OOP is a complication. What you explain here is quite interesting though and I can see some use cases where it could be leveraged. I'm not going to argue anymore about that since I think we both made our points clear. I think further argumentation on that subject would be more dogmatic than useful. Anyhow, thanks for taking time to explain your point!Sport
I advocate that all classes be sealed and all methods be non-virtual until you have a real-world customer-focussed reason to unseal or to make a method virtual. Maybe in 2013 corporate development world it was true, but now it's not. And if you make a library with this approach, your "customers" will choose to write their own library, rather than use yours (or wait for months while you change something). You don't know all cases your class can be used.Gilmore
And other languages somehow live with the ability of total overridability. That's why, for example, ruby has so many gems and a large community, and in dotnet you have to write almost everything by yourself and with many abandoned libraries on github.Gilmore
C
36

In my opinion the currently accepted answer is unnecessarily dogmatic.

Fact is that when you don't mark a method as virtual, others cannot override its behaviour and when you mark a class as sealed others cannot inherit from the class. This can cause substantial pain. I don't know how many times I cursed an API for marking classes sealed or not marking methods virtual simply because they did not anticipate my use case.

Theoretically it might be the correct approach to only allow overriding methods and inheriting classes which are meant to be overridden and inherited but in practice it's impossible to foresee every possible scenario and there really isn't a good reason to be so closed in.

  1. If you don't have a very good reason then don't mark classes as sealed.
  2. If your library is meant to be consumed by others, then at least try to mark the main methods of a class which contain the behaviour as virtual.

One way to make the call is to look at the name of the method or property. A GetLength() method on a List does exactly what the name implies and it doesn't allow for much of interpretation. Changing its implementation would likely be not very transparent so marking it as virtual is probably unnecessary. Marking the Add method as virtual is far more useful as someone could create a special List which only accepts some objects via the Add method etc. Another example are custom controls. You would want to make the main drawing method virtual so others can use the bulk of the behaviour and just change the look but you probably wouldn't override the X and Y properties.

In the end you often don't have to make that decision right away. In an internal project where you can easily change the code anyway I wouldn't worry about these things. If a method needs to be overridden you can always make it virtual when this happens. On the contrary, if the project is an API or library which is consumed by others and slow to update, it certainly pays off to think about which classes and methods might be useful. In this case I think it's better to be open rather than strictly closed.

Cumin answered 29/1, 2013 at 0:10 Comment(2)
Even still you're being too naive. What if I wish to make a JoinedList extends List that dynamically joins two lists together at the time of asking it for its content? Now the GetLength would need overriding. Just always make everything virtual. Obviously an IList interface could solve this as well, but why not both?Handal
Agree with this one, especially now over 10 years later where microservice and service oriented architecture is everywhere. Plus for unit testing its crucial so that its mockableBroz
H
21

No! Because you don't know how your class will be inherited, you should only mark a method as virtual if you know that you want it to be overridden.

Hairline answered 22/1, 2013 at 3:56 Comment(2)
Is marking a method as virtual only because I need to mock unit tests a good practice? (i.e my business logic doesn't require it to be virtual).Eccrine
@Eccrine I would say no to that. Use an interface if possible, or use one of the mocking technologies that works with non-virtual methods. TypeMock, for instance. Making a method virtual is a promise to support all possible overrides of that method. That needs to be properly designed into the class.Hairline
H
4

No. Only methods that you want derived classes to specify should be virtual.

Virtual is not related to final.

To prevent overriding of a virtual method in c# you use sealed

public class MyClass
{
    public sealed override void MyFinalMethod() {...}
}
Heterolecithal answered 22/1, 2013 at 4:1 Comment(1)
FYI, in Java, final on a method means not virtual.Hairline
S
4

Yes you should. I wish to answer a different answer than most other answers. This is a flaw in C#. A defect. A mistake in its design. You can see that when comparing to Java where all methods are "virtual" unless, specified otherwise ("final"). Of course that if there is a class "Rectangle" with a method of "Area", and you wish to have your own class that represents a "Rectangle" with margins. You wish to take advantage of the existing class with all of its properties and methods and you just want to add a property of "margin" that adds some value to the regular rectangle area, and if the area method in Rectangle is not marked virtual, you are doomed. Image please a method that takes an array of Rectangles and returns the sum of the area of all rectangles. Some can be regular rectangles and some with margin. Now read back the answer that is marked "correct" the describe "secuirty issue" or "testing". Those are meaningless compared to the disability to override.

I am not surprised that others answered "no". I am surprised that the authors of C# couldn't see that while basing their language on Java.

Spina answered 27/3, 2020 at 11:57 Comment(3)
Small historical detail: C# is based on C / C++. Of course it is similar to Java, because Java is also based on C / C++. I use both and find no need to "hate one because I use the other".Heiduc
I don't see why different than java automatically makes it a "flaw". If you don't mark it virtual in c# it means you don't want the sub-class to have the ability to modify the behavior. If you want users to do change, then explicitly mark it virtual. It's just different, can't say if one is 100% better than the other.Eccrine
The whole idea, the basic concept of inheritance, the core concept of extending a class, is that the author of the original class, didn't take in considuration some other programmer's use, and therefor, extending/inhertiance allows any programmer to take an existing class and extend it to their own need! the idea behind it, is much larger than comparsion between Java and C#, whomever misses this point, didn't throughly understoon object oriented programming. So it isn't that it's different than java that makes it a "flaw", it's missing the idea beheind it. en.wikipedia.org/wiki/SOLIDSpina
H
2

We can conjure up reasons for/again either camp, but that's entirely useless.

In Java there are millions of unintended non-final public methods, but we hear very few horror stories.

In C# there are millions of sealed public methods, and we hear very few horror stories.

So it is not a big deal - the need to override a public method is rare, so it's moot either way.


This reminds me of another argument - whether a local variable should be final by default. It is a pretty good idea, but we cannot exaggerate how valuable it is. There are billions of local variables that could be, but are not, final, but it has been shown to be an actual problem.

Hoot answered 22/1, 2013 at 16:56 Comment(1)
I've never heard a complaint of a Java method not being final, whereas there are numerous complaints already under this very SO question about C# missing virtuals in its methods.Handal
V
-1

Making a method virtual will generally slow down any code that needs to call it. This slowdown will be insignificant but may in some cases be quite large (among other things, because non-virtual method calls may be in-lined, which may in turn allow the optimizer to eliminate unnecessary operations). It's not always possible to predict the extent to which virtual calls may affect execution speed, and one should generally void doing things which will make code slower except when there's a discernible benefit for doing so.

The performance benefit of making methods non-virtual is probably sufficient in many cases to justify having methods be non-virtual by default, but when classes are designed to be inherited most methods should be virtual and unsealed; the primary usage for non-virtual or sealed methods should be as wrappers for other (possibly protected) virtual methods (code that wants to change the underlying behavior should override the appropriate virtual rather than the wrapper).

There are frequently non-performance-related reasons for marking classes as sealed or limiting inheritance to other classes within the assembly. Among other things, if a class is externally inheritable, all members with protected scope are effectively added to its public API, and any changes to their behavior in the base class may break any derived classes that rely upon that behavior. On the other hand, if a class is inheritable, making its methods virtual doesn't really increase its exposure. If anything, it may reduce derived class's reliance upon the base class internals by allowing them to completely "bury" aspects of the base class implementation that are no longer relevant in the derived class [e.g. if the members of List<T> were virtual, a derived class which overrode them all could use an array of arrays to hold things (avoiding large-object-heap issues), and wouldn't have to try to keep the private array used by List<T> consistent with the array-of-arrays.

Vassell answered 5/6, 2013 at 19:19 Comment(0)
J
-1

No, you should not mark all methods as virtual. You should consider how your class could be inherited. If the class should not be inherited, then mark it sealed and obviously the members should not be virtual. If your class is likely to be inherited, you really should maximize the ability to override the behavior. Therefore generously use virtual everywhere in such classes unless you have a reason not to.

Jaf answered 15/11, 2018 at 20:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.