12

So I wanted to inherit from a sealed class in csharp and got burned. There is just no way to unseal it unless you have access to the source.

Then it got me thinking "why sealed even exists?". 4 months ago. I couldn't figure it out, despite reading many things about it, such as:

I've tried to digest all that since then, but it's just too much for me. Eventually, yesterday I tried it again. I've scanned over all of them again, plus few more:

Finally, after lots of pondering, I decided to heavily edit the original question based on the new title.

The old question were too broad and subjective. It was basically asking:

  1. In the old title: One good reason to use sealed
  2. In the body: How to properly modify a sealed class? Forget about inheritance? Use composition?

But now, understanding (which I didn't yesterday) that all sealed does is preventing inheritance, and we can and should indeed use composition over inheritance, I realized what I needed was practical examples.

I guess my question here is (and in fact have always been) exactly what Mr.Mindor suggested me in a chat: How can designing for inheritance cause extra cost?

cregox
  • 687
  • 6
    The question is worded quite aggressively and sounds like a rant. You should reword it if you want relevant and objective answers. – Euphoric Sep 04 '13 at 16:50
  • @Euphoric Thank you very much for the input! Was this last edit enough? I'm not sure which parts I'm aggressive or ranting. – cregox Sep 04 '13 at 16:58
  • 11
    See Why Are So Many Of The Framework Classes Sealed? by Eric Lippert. He provides several good reasons to seal classes. – Robert Harvey Sep 04 '13 at 17:44
  • @RobertHarvey I can only see 4 chained reasons: (1) opinion (2) lazy (3) because seals exist (4) talks about "secure", but doesn't explain. – cregox Sep 04 '13 at 17:49
  • 9
    Then you didn't read the article. Go back and read it again. It boils down to this: you cannot predict the innumerable ways a client might break your class by extending it. You can blame your clients for that, but you're the one who's going to have to support them. – Robert Harvey Sep 04 '13 at 17:54
  • @RobertHarvey how about we get a room? We're walking in circles here and you're ranting everywhere... I'd invite you, but I don't know how yet. - edit about your last edit: "You can blame your clients for that, but you're the one who's going to have to support them". That's a very good reason I can agree on. Could you elaborate this on an answer? – cregox Sep 04 '13 at 17:57
  • 4
    @Cawas He could, or you could read the article that he linked that explains it in detail. He was just summarizing that article with his comment. – Servy Sep 04 '13 at 18:01
  • 7
    Sorry, but I'm not the one who's ranting here. The answer to your question is very simple: seal a class when you don't want to support inheritance. That's it. – Robert Harvey Sep 04 '13 at 18:02
  • I just did re-read the article and, even with Robert's good answer in its way, I just don't see this article the way you guys do. I stand on the 4 chained reasons and the whole article as insufficient to explain. But that's probably because, as I've stated elsewhere among those links in my question, I never wrote code to be extended by other programmers. So, there you go, this might be my whole problem understanding it. – cregox Sep 04 '13 at 18:40
  • 3
    -1 and Vote to close: Based rude/aggressive/inappropriate replys. Not the kind of culture we want to foster of this site. – mattnz Sep 04 '13 at 20:20
  • @mattnz thanks for the feedback. Would you mind pin-pointing me few instances of the rudeness / aggressiveness / inappropriateness, specially if it's from me, so I can prevent it in the future? (or maybe even edit them now) – cregox Sep 04 '13 at 20:33
  • If a class is not designed for inheritance, inheriting from it probably won't get anything that you couldn't also get via composition. Detailed in my answer here. – Brian Sep 04 '13 at 21:17
  • @Cawas. "How about we get a room...." comment on someone with 50K reps. He knows a thing or two and has spend a lot of time and effort sharing that knowledge, his replies deserve consideration. – mattnz Sep 05 '13 at 02:04
  • @mattnz First of all, thanks for the feedback. Second, thank you again. I won't try to "excuse my behaviour", just explain why I saw no harm in what I said there. Get a room, is a chat room. I honestly meant that. He were sending me comments everywhere, I was able to talk more. I now see how you could interpret it wrong, but that wasn't on my eyes. And just like I don't see at a job my coworker position or at the street, what clothes or shoes someone dresses, I don't look at reps. Even if I do notice it (which wasn't the case). Then again, thank you... I'll try to be more careful. – cregox Sep 05 '13 at 02:31
  • I'd -1 this if I could (not enough rep here) This has been asked and answered in multiple forms elsewhere. (In questions the OP himself linked to.) I'm not sure what more he is looking for. – Mr.Mindor Sep 05 '13 at 15:26
  • @Mr.Mindor so, if you don't understand the question reasoning, -1. Nice. Also, people put this "on hold" despite this yielding to at least 1 great answer and few other answers people liked. People can be so hypocrite some times. – cregox Sep 05 '13 at 15:58
  • If you want to close this, at least state the true reason behind it. The problem isn't because "it's opinion-based" because the answer proves that wrong. Your problem with this question is the discussion that followed it, and usually follows this. I admit I was worried about it when I first wrote it, and I did a terrible job to prevent that from happening. But I think it's just immature closing this given it has already been answered and accepted. You all clearly closed this just to express your frustration with the way this went "forum-mode", like I replied to comments to express mine. – cregox Sep 05 '13 at 16:14
  • 1
    @Cawas not -1 because I don't understand, -1 Because as written it is a duplicate of the questions you linked to. You don't specify what more you are looking for. One of the questions you linked is exactly "Why seal a class?" A question linked from there has an answer in its title: "Why are sealed types faster?" You don't seem to accept or understand the answers to those questions, so you asked the same question again. (edited to remove broken link) – Mr.Mindor Sep 05 '13 at 16:28
  • @Mr.Mindor you said yourself you didn't understand. "I'm not sure what he is looking for" and "the op himself linked to multiple answers elsewhere". I did link and read it all. They were not enough. In fact, can you point any other answer like Dunk's here? I found none and had I found any I wouldn't have asked this question. From that you may be able to understand where my question came from, but so far you clearly couldn't understand. Yes, I didn't specify, of course. That's why it's a question. I don't know what the answer is, that's why I ask. You're missing some basic concepts there. – cregox Sep 05 '13 at 16:37
  • @Cawas Perhaps I should have worded my initial comment differently. You asked a question that had been asked and answered before. You did not specify why the other answers were insufficient. You provided no means for me (or anyone else) to know what more you were looking for. You may have gotten lucky and received an answer worded in a way that you can more easily understand, but this is still a duplicate question, and Dunk's answer, at its core, boils down to the same one Jon Skeet gave: "There is a cost to designing for inheritance". Dunk gave a concrete example of that cost. – Mr.Mindor Sep 05 '13 at 17:05
  • @Mr.Mindor concrete beats abstraction every time dude. You say "or anyone else", yet, there it is, someone answering it. Jon skeet gives reasoning which I disagree to. Concrete evidence from Dunk beats me, though. That's all. My question is not the same as all others just as much it has a unique answer, separate from them all. You could worded your initial comment differently, it wouldn't change the fact you don't get it. Hopefully now you do, like Dunk did. – cregox Sep 05 '13 at 17:11
  • There. Heavily edited. Hope it's much better now. :) – cregox Sep 05 '13 at 19:38
  • Please ask the substantially different question as a different question. The heavy modifications made it so none of the answers made sense to the new question. –  Sep 05 '13 at 19:57
  • @MichaelT It's the same question and accepted answer still makes all sense. Most answers were not making sense to my first intent anyway. If you want to answer a complicated question and don't understand it at first, shouldn't ask for clarifications on comments before bashing on it? - edit to your edit. You just offended me there. I'm abandoning this, at least for now. Screw programmer.sen. [slams the door and leaves furiously] – cregox Sep 05 '13 at 20:00
  • @Cawas I went by "Disclaimer: This have been completely changed from the original question, because it was put on hold." and "I guess my question here is, and have always been in fact, how can designing with inheritance in mind be so troublesome? I need practical examples." which is a different question. The edited question wasn't about sealed - which the answers are about. –  Sep 05 '13 at 20:03
  • @MichaelT The original question was bad. I tried fixing it while people kept answering it. I tried, ok? Nobody really helped me there, just bashed and bashed and bashed. In every way. Now that I finally fix it you REVERT IT?! Why? Because people rushed into their answers?! That's all wrong. Ban me if you want. That was just wrong! I haven't and won't revert YOUR interpretation of what's better. I think you should apologize and put my new question back. – cregox Sep 05 '13 at 20:09
  • The original question was indeed poor. However, it has been answered. There is nothing wrong with having a closed question, but it has answers. Making such a radical change to the question makes a disconnect between the existing answers and the new question - they didn't seem to follow from the question. In such a case, it isn't easily salvageable and maybe shouldn't. If you have a different question than the original one, or change it in a way that the answers (even yours) doesn't make sense, it should be a different question altogether. –  Sep 05 '13 at 20:12
  • I've seem it happen before. First close, next delete. Of course there is something wrong with having a closed question. The change isn't all that radical and it's explained. It's heavy, but not radical. It's coming from the same place it even asks, before anything " why sealed even exists ", thus giving room to anyone approach that first to kill the rest, which even happens with the accepted answer. To me that disconnect between answers and my question was always there. – cregox Sep 05 '13 at 20:24
  • 1
    @Cawas It would take a substantial mustering of delete votes to delete a question that has answers which sum to 45 votes (more than typically easily found). It is unlikely to be deleted as it stands. On the other hand, your revised question invalidates 8 answers including one at +18 - this is bad. If you feel that you need to make such a substantive change, please work with a moderator (probably chat) to delete all the answers that your revised question doesn't answer. –  Sep 05 '13 at 21:04
  • @MichaelT let us continue this discussion in chat. I could go and add a comment about the change to every answer if you want, apologizing for my first question. But I don't think the new question invalidates any answer. It just makes them as disconnected (and non sensical) as I first saw them. – cregox Sep 05 '13 at 21:22
  • People need to realise that not everyone on StackExchange is a native English speaker, like the OP for example. They're trying their best to express themselves and sometimes it can sound rude, but it's not their intention. – David Klempfner Sep 28 '21 at 03:38
  • 1
    @david thanks for the compliment, but i learned english together with video gaming, movies, programming, and terrible school classes (in this order of contribution to my learning, nobody really speaks good english in brazil) and, even more, i could only really speak with someone when i was 23 and then moved for 1 year to a english speaking area for the first time, back in 2004. far from being native, and forever learning. and i 100% agree with your feeling. i would just replace the "need" (in "people need to realise") for "should probably", because i don't know what's best for everyone. – cregox Oct 06 '21 at 06:02

9 Answers9

30

This is not so difficult to comprehend. sealed was created SPECIFICALLY for Microsoft in order to make their lives easier, save tons of money and help their reputation. Since it is a language feature everyone else can use it also but YOU will probably never ever need to use sealed.

Most people are complaining about not being able to extend a class and if they do then they say well everyone knows it is the developers responsibility to make it work correctly. That is correct, EXCEPT those same people have no clue on the history of Windows and one of the problems sealed is trying to solve.

Let's suppose a developer extended a .Net core class (because sealed did not exist) and got it to work perfectly. Yay, for the developer. The developer delivers the product to the customer. The developer's app works great. The customer is happy. Life is good.

Now Microsoft releases a new operating system, which includes fixing bugs in this particular .Net core class. The customer wants to keep up with the times and chooses to install the new operating system. All of a sudden, the application that the customer likes so much no longer works, because it did not take into account the bugs that were fixed in the .Net core class.

Who gets the blame?

Those familiar with Microsoft's history know that Microsoft's new OS will get the blame and not the application software that misused windows libraries. So it then becomes incumbent on Microsoft to fix the problem instead of the application company who created the problem. This is one of the reasons why Windows code became bloated. From what I've read, the Windows operating system code is littered with specific if-then checks for if a specific application and version is running and if so then do some special processing to allow the program to function. That's a lot of money spent by Microsoft to fix another company's incompetence.

Using sealed doesn't completely eliminate the above scenario, but it does help.

Robert Harvey
  • 199,517
Dunk
  • 5,069
  • Good enough for me. This also tells me a lot of people are probably abusing seal and using it very wrongly... But not as many people like me, who can't understand this at first (or second, or even third for that matter). Thanks, dude! – cregox Sep 04 '13 at 18:56
  • 6
    @Cawas It's pretty hard to abuse it. Eric Lippert has stated on a number of occasions he wishes that classes, like methods, were all sealed by default, unless specifically unsealed, simply because so few classes are actually designed to be inherited. It's much more likely that your class wasn't built to support it, and you should be ensuring that you have spent that dev time if you're going out of your way to mark it as unsealed. – Servy Sep 04 '13 at 18:58
  • 1
    I think if people are using sealed for their internal development software they are probably misusing it or are just wasting company time trying to be too perfect. I say probably because there are always cases that one can come up with that make sense in some particular scenario. However, for those developing library-type software, I would suspect it to be very useful for the same reasons that Microsoft decided there was a need for it. – Dunk Sep 04 '13 at 19:03
  • @Servy I don't know Eric or any well known dudes, but from where I stand I bet there are many other well known architects out there that would defend sealed shouldn't be default - because it isn't! But I'd love to chat about all this with one of you, if you will... I still read that article as just reasoning this awesome and actual issue Dunk gave us, right there. The same way I'd probably read that Eric's statements, about "it's hard to design to be inherited", I've read so many places. – cregox Sep 04 '13 at 19:06
  • 4
    @Cawas The vast majority of classes written by most developers will never need to be inherited, and aren't written to support inheritance. This can quickly and effectively be conveyed to readers/users of the code by making the type sealed. If it were in fact the default option then it would mean that if someone was inheriting from a type then they would know that it's built to support it. – Servy Sep 04 '13 at 19:10
  • @Servy Will never need to be inherited: agree. Aren't written to support inheritance: how can I disagree? [/rhetorical] But they're also not written to support non-inheritance, if that makes any sense. Means people don't write thinking about any one else going through their code, to good or to bad. So that's a non sequitur as well. (Man, we commit logical fallacies all the time). If sealed is not default, from my point of view, the reasons you're not presenting are actually the prevailing ones. Don't know why you don't bring them. – cregox Sep 04 '13 at 19:17
  • @Cawas So you know a bunch of reasons that you think are better than those mentioned, but are just waiting for others to bring them up instead? Then why ask the question, or at least why not bring those points up yourself if you think they're better? As for people truly relying on the lack of inheritance, that tends to be more explicitly thought through in library types where they're writing out reasons and thinking hard about the decision, that's true, and most LOB devs won't bother. It's still rather common for them to rely on assertions without always thinking about it, or realizing it. – Servy Sep 04 '13 at 19:24
  • 3
    Unsealing a class would not mean that the class was built to support it. It just means that somebody wanted to inherit from the class and unsealed it. In the best case, using sealed will simply cause developers to rewrite existing functionality (equivalent to the sealed class) but more often than not, if the source code is available, they'll simply unseal it without taking into account any consequences. Having sealed be specifically and rarely set, is better because then the developer might want to figure out why this class is sealed. Too many sealed classes and they won't care why. – Dunk Sep 04 '13 at 19:25
  • @Servy because I don't know. I never said I did. Much the opposite, I'm all the time saying that's all I can see. I've stated my point of view very eloquently in my question. I'm making assumptions, just like you are. "most LOV devs won't bother" -> that's an assumption. "It's still rather common for them" -> You're implicitly assuming "them" as "everyone" or "a lot of people" or "majority". In any case, amazing Dunk nailed it again. Sound counter-reasoning although also makes an assumption in the end: "better because the developer might want to figure out why". – cregox Sep 04 '13 at 20:50
  • If you don't have to support a class, then sealing a class doesn't get you much (though it offers an opportunity for minor optimizations). You and your team probably won't accidentally inherit from an unsealed class, and are probably going to be peeking at its source code in the event you inherit from it. Of course, on a larger team this may no longer hold, since it might be necessary to treat some classes as black boxes. – Brian Sep 04 '13 at 21:27
  • 1
    Also security is a reason to use it! Consider a sandboxed application trying to access a file. The sandbox might test the filename-strings, but what if an attacker could send you a mutable String and then they mutate it after the security-check but before the I/O? I believe that type of scenario is why Java's String is marked final (similar to sealed) and I bet the same logic underpins some C# decisions. – Darien Sep 04 '13 at 21:32
  • 1
    If you are able to inject ANY code onto the server then you can compromise these kinds of security checks, making the class sealed makes little difference when someone can use a handle to the same object and make public calls to the object to change its data. – Michael Shaw Sep 04 '13 at 22:04
  • I've extended my answer to cover why this is a really weak agument for sealed. – Michael Shaw Sep 04 '13 at 22:05
  • @Ptolemy I suggest you re-read my comment. If the class (e.g. String) is immutable, then by definition you can't "use a handle to the same object and make public calls to change its data", can you? All the public calls are read only. The whole point of sealing is to prevent people from changing that! – Darien Sep 04 '13 at 22:25
  • At the end of the day, If you are in the situation where you cannot trust the code running in your process, than relying on your code running properly is dangerous. using .NET managed C++ you can access raw memory, write new CIL instructions on the fly etc.. The very fact that you tell me that you rely on that memory contents not being changeable tells me that when you find a way to abuse that trust, there is a security hole. – Michael Shaw Sep 04 '13 at 22:48
  • @Darien more assumptions... "I believe", "I bet", "what if"... I don't understand how a compiler modifier such as sealed or private can have any effect in a compiled code. I'm also just making an ignorant assumption here but, as I understand it, they only act at compile time and can not prevent code injection. – cregox Sep 05 '13 at 16:24
  • @Cawas C#'s CIL is like Java bytecode, and in both cases there are runtime sanity/verification checks as execution begins. These checks include preventing final/sealed violations. Remember, this is about a trusted base platform running untrusted/sandboxed code, not about somebody creating their own hacked platform from scratch. – Darien Sep 05 '13 at 17:08
  • @Darien you might be on something here. I understand we can compile bytecode with .NET and, to run a .exe file on windows generated by C# .NET, still require having installed a .NET library or any other kind of "vitual machine" (taking terms from Java again). I think that's not how I use C# primarily so I've missed that - but even so maybe the binary itself have a self-contained virtual machine and I wouldn't know. That sounds like a very good (even if rare) reason to use sealed. Now I just needed to take all assumptions out and see if this applies in practice. – cregox Sep 05 '13 at 17:19
  • @Ptolemy So you're saying that un-sandboxed code can defeat a sandbox? How is that news? – Darien Sep 05 '13 at 17:20
  • @darien, I was talking more generally that just escaping .NET's security restrictions, but even if you are sandboxed like that, relying on sealed is a risk. Yes it would take another flaw to expose it, but you are making that other flaw more of a risk as well. Especially as when its 'discovered' it gets classed as low risk, because it only lets you modify memory in your own process.... – Michael Shaw Sep 05 '13 at 17:50
24

sealed is used to indicate that the writer of the class hasn't designed it to be inherited. Nothing less, nothing more.

Properly designing an interface is already difficult enough for lots of programmers. Properly designing a class which can be potentially inherited adds difficulty and lines of code. More lines of code written means more code to maintain. To avoid this increasing difficulty, sealed can show that the class was never intended to be inherited, and in this context, sealing a class is a perfectly valid solution to a problem.

Imagine the case where the class CustomBoeing787 is derived from Airliner. This CustomBoeing787 overrides some protected methods from Airliner, but not all of them. If the developer has enough time and it's worth it, he can unit test the class to ensure that everything works as expected, even in a context when non-overriden methods are called (for example protected setters which change the state of the object). If the same developer (1) doesn't have time, (2) doesn't want to spend additional hundreds or thousands of dollars of his boss/customer, or (3) doesn't want to write additional code he doesn't need right now (YAGNI), then he can:

  • either release the code in the wild as is, considering that it's the concern of the programmers who will maintain this project later to care about potential bugs,

  • or mark the class as sealed to explicitly show to the future programmers that this class is not intended to be inherited, and that unsealing it and using it as a parent should be done at your own risk.

Is it a good idea to seal as many classes as possible, or as few as possible? From my experience, there is no definitive answer. Some developers tend to use sealed too much; others don't care about how the class would be inherited and the problem it can cause. Given such usage, the problem is similar to the one which consists in determining whether programmers should use two or four spaces for indentation: there is no right answer.

  • All right... Sorry if I sound aggressive again, but I just want to be clear and assertive here... I can only understand what you just wrote in either of 2 ways, if you were to write a tl;dr here. It's either "No, there is not a single good reason", or "I think there is no good reason, but I don't know as well.". To me "no definitive answer" is either one of those. – cregox Sep 04 '13 at 17:07
  • 6
    sealed is used to indicate that the writer of the class hasn't designed it to be inherited. That's your single good reason. – Robert Harvey Sep 04 '13 at 17:53
  • 1
    That's as a good reason as giving you a bicycle without lights and enforcing, somehow, you can't add lights. – cregox Sep 04 '13 at 18:08
  • 2
    @Cawas How so? In that context it's not important for the bike builder to ensure that the bike doesn't have a light, but it often is important for the user of a type to ensure that the implementation is a particular exact implementation. You enforce the constraints you need to. In some cases people may add a constraint that isn't actually needed; you have provided an example of that. Just because the constraint is mis-used in one place doesn't mean that you should never constrain anything ever. – Servy Sep 04 '13 at 18:12
  • Well yeah. But sealed is a tool that, from my point of view, can only be abused or miss-used. Give me then the counter example in how it can be properly used, since you do have "some cases". – cregox Sep 04 '13 at 18:24
  • MainMa, about your edit... I think you're just reasoning from your premise. And, unless you've got Dunk's fact as premise, you're just making believe there is a practical reason there. And there is, but you're not showing it, you're just supposing it. The reason to use it isn't the supposition, is the fact of what have happened. That's a good reason. – cregox Sep 04 '13 at 19:20
  • 1
    Also security is a reason to use it! Consider a sandboxed application trying to access a file. The sandbox might test the filename-strings, but what if an attacker could send you a mutable String and then they mutate it after the security-check but before the I/O? I believe that type of scenario is why Java's String is marked final (similar to sealed) and I bet the same logic underpins some C# decisions. – Darien Sep 04 '13 at 21:29
  • Can you provide an example of a class that is and is not designed for inheritance? – David Klempfner Sep 28 '21 at 03:26
6

When a class is sealed it allows code using that type to know exactly what they're dealing with.

Now in C# string is sealed, you can't inherit from it, but let's assume for a second that that wasn't the case. If you did, then someone could write a class like this:

public class EvilString// : String
{
    public override string ToString()
    {
        throw new Exception("I'm mean");
    }
    public override bool Equals(object obj)
    {
        return false;
    }
    public override int GetHashCode()
    {
        return 0;
    }
}

This would now be a string class that is violating all sorts of properties that the designers of string knew to be true. They knew that the Equals method would be transitive, this is not. Heck, this equals method isn't even symmetric, as a string could be equal to it but it wouldn't be equal to that string. I'm sure there are all sorts of programmers who have written code under the assumption that the ToString method of string won't throw an exception for non-null values. You will now be able to violate that assumption.

There are any number of other classes we could do this for, and all sorts of other assumptions that we could violate. If you remove the language feature for sealed then the language designers now need to start accounting for things like this in all of their library code. They need to perform all sorts of checks to ensure that extended types of the types they wish to use will be written "properly", which can be a very expensive thing to do (both in dev time, as well as at run time). By being able to seal a class they can ensure that this isn't possible, and that any assertions they make about the implementation details of their own types can't be violated, except for those types that are intentionally designed to be extended. For those types designed to be extended you'll find the language code needs to be much more defensive about how it deals with them.

Servy
  • 1,976
  • But you are able to violate that assumption in your code. It's not like you're grabbing String's source and editing it. The designers wouldn't need to account for this because it's 1 leaf, 1 branch, 1 client using it at its own risk and discretion. It won't disseminate from there, unless other clients prefer to do so. And so on. – cregox Sep 04 '13 at 18:05
  • 3
    @Cawas And if an exception is throw at an unexpected time and a resource is leaked as a result, or a class is left in an indeterminate state and functions inappropriately? This case is a bit silly, but it could easily be the case that someone writes an implementation that they think is sensible, but occasionally throws when it shouldn't, or doesn't work with certain values. They'll then complain when the language code doesn't work. It's preferable to just not let people do things that the language won't be able to support. – Servy Sep 04 '13 at 18:08
  • In any case you are talking about building a compiler. There are many such sealed features built-in there that's not exposed for us to use. It still doesn't explain why use it outside such a narrow scope and, being as narrow as compiler code, doesn't even explain sealed existence. – cregox Sep 04 '13 at 18:15
  • 3
    @Cawas The string type isn't compiler code. It's part of the language code. Completely different. In any case, I just picked one example. You could pick up most any sealed class in the entire BCL and use that as an example. – Servy Sep 04 '13 at 18:17
  • 6
    @Cawas: I think what you might be missing here is the customer support aspect. If you allow a class to be inheritable, customers are going to inherit from it, and then they're going to call you when it breaks. You can tell them all day long that they inherit from that class at their own risk, but you're still going to get the call, because you allowed them to inherit from it, so they assume that it is safe to do so. – Robert Harvey Sep 04 '13 at 18:20
  • @RobertHarvey there you go. That is it right there. Please put this as an answer so I can accept it. That's a very good reason to use it, all I asked. – cregox Sep 04 '13 at 18:27
4

First of all, you should read Eric Lippert's post on why Microsoft seal their classes.

Link

Secondly, the sealed keyword exists to do exactly what it does - prevent inheritance. There are many situations where you want to prevent inheritance. Consider a class that you have a collection of. If your code depends on that class working in a particular fashion you don't want someone overriding one of the methods or properties in that class and causing your application to fail.

Thirdly, using sealed encourages composition over inheritance, which is a good habit to get into. Using composition over inheritance means that you can't break Liskov's substitution principle and you're following the Open/Closed principle. sealed is therefore a keyword that assists you in following two of the five most important principles of o-o programming. I'd say that makes it a very valuable feature.

Glorfindel
  • 3,137
Stephen
  • 8,848
  • 3
  • 30
  • 43
  • First part is already pointed out in the question comments. Second part is just more reasoning without real causations. Third part, even though already approached elsewhere, might have something to it. I'd focus on that one. – cregox Sep 05 '13 at 16:19
  • 1
    the third point doesn't encourage composition over inheritance, it completely eliminates inheritance as an option, even if that was the best overall choice. – Michael Shaw Jun 02 '16 at 11:21
  • That depends if you control the codebase or not. If you seal classes you can always unseal them later if needed. – Stephen Jun 02 '16 at 22:02
3

Is there any good reason to use sealed?

Enh? Not often. I will only used sealed when I have an immutable type (or some other limitation) that really really needs to remain immutable and I cannot trust inheritors to furfill that requirement without introducing subtle, catastropic bugs into the system.

Suppose there is a good reason to use sealed and we should use it as default for everything, what we do with inheritance?

We use inheritence for those things that are not default. Even if composition is favored over inheritence (and it is), that doesn't mean inheritence is to be discarded. It means that inheritence has some intrinsic problems that it introduces into design and code maintainability and composition does much of the same thing with (in general) less problems. And it means that even if composition is favored that inheritence is good for certain subsets of problems.

I don't mean to be too mean but if you've just now heard of SOLID and unit testing, maybe you should get out from underneith your rock and actually write code. Things aren't clear cut, and rarely will "always do X" or "never use Y" or "Z is best" be the right way (like it seems you gravitate towards based on your question's views). As you write code you can see cases where sealed could be good and cases where it causes you grief - just like any other tradeoff.

Telastyn
  • 109,398
  • To me, this and the "to avoid having to support inheritance to clients" that Robert don't want to elaborate are the most promising answers... Maybe you could elaborate more on those cases where you do use sealed, please? – cregox Sep 04 '13 at 18:17
  • @Cawas - I'm not sure I can well. I very rarely do it, and it's often a tradeoff where the guarantee that something stay immutable (to make performance optimizations, design simplification) is worth the inability to inherit from the object. – Telastyn Sep 04 '13 at 19:33
  • That's cool. Dunk already dunked it! :P Thanks so much for the answer. And you were the only one to pick up my "subtle hints" about my expertise. Seems like people were assuming I knew more, I don't know... But I wish "just coding" would take me out of this rock. Maybe I do apply those concepts in some way, just not as procedurally as I probably should. – cregox Sep 04 '13 at 19:37
2

I think this question doesn't have objective answer and that it all depends on your perspective.

One side, some people want everything "open" and burden of ensuring everything is working correctly is on person who extends the class. This is why classes are open to inheritance by default. And why Java methods are all virtual by default.

On the other side, some want everything to be closed by default and to provide options to open it. In this case, it is base class's author who needs to ensure everything he makes "open" is safe to use in any way imaginable. This is why in C# all methods are non-virtual by default and need to be declared virtual to be overriden. It is also for those people, that need to be way to circumvent "open" defaults. Like making class sealed/final, because they see someone deriving from the class a big problem to their own class's design.

Euphoric
  • 37,384
  • This is more like it! This might be a good reason... "Because people want to close it". And it's also what I'm trying to say in the question: looks like non-virtual classes in C++ can be overridden. sealed can't. How can we inherit from them? All I read is we can't. Ever. I don't know. I've been back and forth on this subject for 4 months now, since I first heard about sealed. And I still don't know how to do it right when I need to modify anything on a sealed class. So, I see no "option to open it"! – cregox Sep 04 '13 at 17:28
  • 5
    This is not why C++ class methods are not virtual by default. Making a method virtual means the there has to be additional overhead on the method lookup table, and C++ has the philosophy that you only pay for overhead when you want the feature. – Michael Shaw Sep 04 '13 at 17:31
  • @Ptolemy Ok, I removed it. I should have never written it, because I knew people start complaining about it. – Euphoric Sep 04 '13 at 17:35
  • hey, I completely appreciate that if you want to claim that people want to write closed classes by default, and have to actively choose to open them then you are going to have to clutch at straws – Michael Shaw Sep 04 '13 at 17:38
  • 1
    IMO it's extremely similar to the private/protected/public debates when it comes to APIs: It strongly depends on who controls the class, who wants to inherit the class, communication between the two, and how often new versions come out. – Darien Sep 05 '13 at 17:29
-2

the problem with sealed in C# is that its rather final. In 7 years of C# commercial development, the only place I have seen it used is on Microsoft .NET classes where I feel I had a legitimate reason to extend a framework class to implement adjusted behaviour, and because the class was sealed, I could not.

It is impossible to write a class thinking about every possible way it could be used, and deciding that none of them are legitimate. Likewise if framework security is dependent on the class not being inherited, then you have a security design flaw.

So, in conclusion, I'm firmly of the view that sealed serves no useful purpose, and nothing I have read here so far has changed that view.

I can see there have so far been three arguments that justify sealed placed so far.

  1. Argument 1 is that it eliminates a source of bugs when people inherit from classes and then have increased access to the internals of that class without really understanding the internals properly.

  2. Argument 2 is that if you extend a microsoft class and then microsoft implement a bug fix in that class but your extention relied on that bug then your code is now broken, microsoft gets the blame, and sealed prevents that

  3. Argument 3 is that as the developer of the class, its my choice whether to allow you to extend it, as part of my design of the class.

Argument 1 seems to be an argument that you the end programmer don't know how to use my code. That may be the case, but if you still allow me to access the objects interface it still holds true that I am using your object, and making calls to it without understanding how to use it, and so can make just as much damage that way. This is a feeble justification of the need for sealed.

I understand where the factual base for arg 2 comes from. In particular when microsoft put additional OS checks on win32 api calls to identify malformed calls, which have improved the general stability of the Windows XP compared to Windows NT, but at the short term cost that many apps were broken when Windows XP was released. Microsoft resolved this by putting 'rules' in for these checks to say, ignore when app X breaks this rule, its a known bug

Argument 2 is a poor argument because sealed at best makes next to no difference to this because if there is a bug in the .NET library you have no choice but to find a work around, and when the microsoft fix comes out, its quite likely means that your work around which depends on the broken behaviour is now broken. Whether you worked around this by using inheritance or by some other additional wrapper code, when the code is fixed, your work around will be broken.

Argument 3 is the only argument that has any substance to justify its self. But it is still weak. It just goes against the grain of code reuse.

Michael Shaw
  • 9,935
  • 1
  • 24
  • 36
  • I've voted +1, someone voted urs and mine down... We're losing this battle dude! :P Just wished the downvoting system required people to give their reasons. :( – cregox Sep 04 '13 at 17:33
  • 1
    Yep, theres plenty of people down voting, but I have yet to see a thought out reasoned argument for when sealed is an appropriate design choice, considering that a sealed class CANNOT be unsealed. – Michael Shaw Sep 04 '13 at 17:42
  • Yes, considering a sealed class cannot be unsealed is key here. I'll add that to the question! :-) – cregox Sep 04 '13 at 17:42
  • @Ptolemy A sealed class most certainly can be unsealed. Unsealing a class is not a breaking a change, while sealing a class is. If the writer of the class modifies it such that it is able to properly support being overridden then they can unseal it. – Servy Sep 04 '13 at 17:44
  • 2
    /me sends an email to microsoft, please can you unseal class X for me and ship out a new release of .NET. kind regards,.... Like I said, the only time in commercial development I have seen a sealed class, it was not possible to unseal it. – Michael Shaw Sep 04 '13 at 17:46
  • @Servy Ptolemy was ahead of me, and much funnier I could've been! :P Point is: we can't unseal if we don't have access to the source. – cregox Sep 04 '13 at 17:47
  • 6
    It is impossible to write a class thinking about every possible way it could be used -- That's precisely the reason many Framework classes are sealed... It eliminates the need to think about every possible way someone might extend the class. – Robert Harvey Sep 04 '13 at 17:47
  • 5
    If you could unseal it, there wouldn't be much point in sealing it, would there? – Robert Harvey Sep 04 '13 at 17:48
  • 1
    Actually by sealing a class, you DO have to think about EVERY reason why someone might legitimately want to extend it, and decide that none of them are valid reasons. – Michael Shaw Sep 04 '13 at 17:53
  • @RobertHarvey "It is impossible to write a class thinking about every possible way..." that's a non sequitur. Google for it. Means you're making a logical fallacy. And the point of sealing a unseleable class is difference between enunciating and enforcing your intent. – cregox Sep 04 '13 at 17:53
  • 2
    @Ptolemy Allowing people to extend your class is a feature. One that consumes a significant amount of development effort. It's a feature only worth justifying if the author of the class can see enough benefit in potential extensions to justify the effort. If they can't justify the effort, and therefore the type and its users aren't built to support extension, then it's important to prevent it, otherwise you'd be technically able to extend the type, but it's unlikely to work properly when you do so. – Servy Sep 04 '13 at 17:55
  • 2
    @Cawas: You're just being difficult. – Robert Harvey Sep 04 '13 at 17:59
  • @RobertHarvey you and about 5 or 6 more people reading this who can vote here agree with you. Only 1 is agreeing with my opinion. It's not a very fair "fight" and some of your guys are fighting dirty (downvoting without explaining why). I go "easy", I die. It's not easy to me this and, as I hope it's clear by now if you do read all this thread, I'm more than willing to change opinion. In my head, I'm assuming the sealed does have a good reason to exist or else I wouldn't even be here. I just want to see that as you guys do. – cregox Sep 04 '13 at 18:46
  • 2
    @Cawas: It's not a fight, debate or discussion. This is a Q&A site, not a forum. You should only expect answers and clarifications, as such. – Robert Harvey Sep 04 '13 at 19:23
  • @RobertHarvey Saying "you're just being difficult" is picking a fight, dude. Stop being so self absorbed, or something. I know what's a Q&A site and I hate forums. I hate we're having all these discussions, but you were not helping against it, as well. – cregox Sep 04 '13 at 19:25
  • If String was unsealed, you could make mutable String instances. If that isn't terrifying, you're not thinking hard enough about how it could be both a source of bugs and a source of security-holes. Sealing is therefore an important feature when it comes to creating the core runtime and libraries, even if it sees limited use at the application-level. – Darien Sep 04 '13 at 21:34
  • But using a combination of Cil and managed C++ I suspect I could get your immutable string value type considered deleted, and still have a C++ pointer to that memory, whilst your library things its still got a valid and immutable string value type. – Michael Shaw Sep 04 '13 at 22:14
  • @Ptolemy about your latest edits, I couldn't agree more. I may be completely mistaken here, but I feel like if we put this question to a different community, maybe python or ruby, the bashing might be on all of the other answers here and our 2 answers would be more upvoted... And maybe people would also not take things so personally. That being said... Argument 2 isn't just that. As I see it, sealed must indeed have helped Microsoft there. Just by making people to stop and think about what they're doing, MS must have got a lot less support request. I hate assuming, but it's all I've got. – cregox Sep 05 '13 at 16:31
  • Having supported users, my guess is that it made bugger all difference to Microsoft, as most users cannot support from Microsoft. It may help much smaller providers of libraries, but I'd also guess that most of the time it just meant the support requests came in as 'how can I do this' rather than as a bug report. – Michael Shaw Sep 05 '13 at 17:54
-7

I only use sealed keyword on classes that contain only static methods.

-8

As evident by my question, I'm no expert here. But I see no reason for sealed to even exist.

It seems to be made to help code architects to design an interface. If you want to write a class that will go out in the wild and many people will inherit from it, modifying anything in that class can break it for too many people. So we can seal it and nobody can inherit. "Problem solved".

Well, looks like "covering a spot and uncovering another". And it's not even solving a problem - it's just eliminating a tool: inheritance. As any tool, it has many usages and inheriting from a unstable class is a risk you take. Whoever took that risk should know better.

Maybe there could be a keyword stable, so people would know it's safer to inherit from it.

cregox
  • 687
  • 3
    "Problem solved" -- Exactly. – Robert Harvey Sep 04 '13 at 17:48
  • @RobertHarvey It's not solved, as explained right in the next paragraph. – cregox Sep 04 '13 at 17:50
  • 9
    You're just mad because you can't extend the class. That doesn't mean that sealed is not a useful tool to the framework designers. Classes in a framework should be black boxes; you should not have to know about the internals of a class to be able to use it properly. Yet that's exactly what inheritance demands. – Robert Harvey Sep 04 '13 at 17:51
  • I never said it's not useful. I say I don't see its usage, and point out why. Please, I'm begging you, give me a good reason to use it! Even if it's just "because I want to follow a closed design pattern", that's fine. I don't see anyone giving that reason, explicitly. – cregox Sep 04 '13 at 17:55
  • 7
    The good reason is that you don't have to support inheritance on a sealed class. – Robert Harvey Sep 04 '13 at 17:59
  • I just want to know (A) how to properly use it and (B) if I should use it. And I don't get beyond point (A). But I'll get there, eventually... And I hope I'm able to report back. ;-) – cregox Sep 04 '13 at 18:50