views:

317

answers:

3

Why would anyone want to mark a class as final or sealed?

+9  A: 

Because creating a type for inheritance is much harder work than most folks think. It is best to mark all types this way by default as this will prevent others from inheriting from a type that was never intended to be extended.

Whether or not a type should be extended is a decision of the developer who created it, not the developer who comes along later and wants to extend it.

Andrew Hare
Interesting that this was downvoted - I would like to hear a counter-argument to what I have written here.
Andrew Hare
I'm with the downvoter on this, but don't consider it a -1 situation :) Working with 3rd party code that has been restrictively sealed can make life miserable, especially when bugs need to be worked-around. More than once, I've had to wrap buggy classes because the protection levels were needlessly restrictive.
spender
The performance benefit is the only advantage that seems reasonable to me.
Velika
Use AOP, if present, to work around this. <g>
James Black
Why shouldn't I, the developer using a class, decide whether I should subclass it or not? If it's not designed for inheritance, I can take that into account.
David Thornley
"Why shouldn't I, the developer using a class, decide" For the same reason why you should not decide should you access private member or not. Because developer who designed class decided it would be safer. Sure, there are more strict and more soft approaches. You will not find private and sealed/final keywords in javascript and other "soft" languages.
Pavel Feldman
+12  A: 

According to Wikipedia, "Sealed classes are primarily used to prevent derivation. They add another level of strictness during compile-time, improve memory usage, and trigger certain optimizations that improve run-time efficiency."

Also, from Patrick Smacchia's blog:

  • Versioning: When a class is originally sealed, it can change to unsealed in the future without breaking compatibility. (…)

  • Performance: (…) if the JIT compiler sees a call to a virtual method using a sealed types, the JIT compiler can produce more efficient code by calling the method non-virtually.(…)

  • Security and Predictability: A class must protect its own state and not allow itself to ever become corrupted. When a class is unsealed, a derived class can access and manipulate the base class’s state if any data fields or methods that internally manipulate fields are accessible and not private.(…)

Those are all pretty good reasons - I actually wasn't aware of the performance benefit implications until I looked it up just now :)

The versioning and security points seem like a huge benefit in terms of code confidence, which is very well justified on any kind of large project. It's no drop-in for unit testing, of course, but it would help.

Mark Rushakoff
FWIW: I'm pretty sure that the HotSpot doesn't get much performance benefit from this, as it supports dynamic deoptimization. Basically, it assumes that all methods are non-virtual until it actually loads another version of the method. When that happens it goes back and "deoptimizes" any places where it made a non-virtual call to instead make a virtual call.
Laurence Gonsalves
Versioning? I don't follow this. It just sounds like your saying "you can remove the 'sealed' property from the class and recompile"-that doesn't speak to why you'd do it in the first place.Performance? Interesting!Security? Sub Classes can only access what the base class permits. If the base class wishes to "protect" its data, it shouldn't use "Protected" properties. That's not a reason to seal the whole class. I'm missing it .
Velika
I think the versioning would apply if you released a "beta" class, perhaps internally within your company. Force it to be sealed until that class reaches "release" status. Security? Public base class with protected member, sealed derived class can access the member, but nobody else can derive from *that* class and mess with the member.
Mark Rushakoff
Versioning is about changing base class and not breaking all the subclasses.
Pavel Feldman
+3  A: 

Joshua Bloch in his book Effective Java talks about it. He says "document for inheritance or disallow it". The point is that class is sort of a contract between author and client. Allowing client to inherit from base class makes this contract much more strict. If you are going to inherit from it, you most likely are going to override some methods, otherwise you can replace inheritance with composition. Which methods are allowed to be overridden, and what you have to do implementing them - should be documented, or your code can lead to unpredictable results. As far as I remember, he shows such example - here is a collection class with methods

public interface Collection<E> extends Iterable<E> {    
  ...
  boolean add(E e);
  boolean addAll(Collection<? extends E> c);
  ...
}

There is some implementation, i.e. ArrayList. Now you want to inherit from it and override some methods, so it prints to console a message when element is added. Now, do you need to override both add and addAll, or only add? It depends on how addAll is implemented - does it work with internal state directly (as ArrayList does) or calls add (as AbstractCollection does). Or may be there is addInternal, which is called by both add and addAll. There were no such questions until you decided to inherit from this class. If you just use it - it does not bother you. So the author of the class has to document it, if he wants you to inherit from his class.

And what if he wants to change the implementation in the future? If his class is only used, never inherited from, nothing stops him from changing implementation to more efficient. Now, if you inherited from that class, looked at source and found that addAll calls add, you override only add. Later author changes implementation so addAll no longer calls add - your program is broken, message is not printed when addAll is called. Or you looked at source and found that addAll does not call add, so you override add and addAll. Now author changes implementation, so addAll calls add - your program is broken again, when addAll is called message is printed twice for each element.

So - if you want your class to be inherited from, you need to document how. If you think that you may need to change something in the future that may break some subclasses - you need to think how to avoid it. By letting your clients inherit from your class you expose much more of internal implementation details that you do when you just let them use your class - you expose internal workflow, that is often subject to changes in future versions.

If you expose some details and clients rely on them - you no longer can change them. If it is ok with you, or you documented what can and what can not be overriden - that's fine. Sometimes you just don't want it. Sometimes you just want to say - "just use this class, never inherit from it, because I want a freedom to change internal implementation details".

So basically comment "Because the class doesn't want to have any children and we should respect it's wishes" is correct.

So, someone wants to mark a class as final/sealed, when he thinks that possible implementation details changes are more valuable than inheritance. There are other ways to achieve results similar to inheritance.

Pavel Feldman