Most programming languages nowadays support sealed classes (sometimes final classes), which prevent the class from being extended or subclassed. Some languages seal their classes by default, like Kotlin, while others require you to explicitly seal them with a modifier keyword, like C#.

Now I don't just prefer the C# way, but as a matter of fact I have never sealed a single class of mine, and neither should you.

What is sealing, really?

Simply put, sealing is equivalent to claiming that:

I know better than those who come after me. I know what others will need this class for in the future even after I've left the company. I know all the possible use-cases and what external users and clients will need this class for.

Now I don't know how good the lead developers in your company are, but I'm personally not willing to make claims that require me to see the future—thus I always leave my classes unsealed.

What are the upsides of sealing a class?

Performance. A compiler can make certain optimizations based on knowing that the class won't be extended. If you're working on performance critical code, then yes, sealing a class is a reasonable thing to do.

That's it. Any other upsides one can think of are mere misunderstandings. Refer to the FAQ section below, which I will be updating to debunk these misunderstandings as they arise.

What are the downsides of sealing a class?

If you made a mistake in your class, nobody else can fix it in theirs, instead they will have to wait for you to fix the mistake in your original, sealed class. Which is a noble approach in theory, but the novelty quickly wears off in practice when the project already has a thousand issues on GitHub and the maintainer is on a vacation in Majorca.

Similarly, if someone needs a small variation of your class that you failed to predict 10 years ago, they're out of luck. Imagine having to rewrite the entire Car class from scratch because the ICE people sealed their classes and now you can't extend your EV from them. Or having to copy&paste the whole flying and rotor logic into a drone because people in 1980s didn't think helicopters could ever get small enough to not carry personnel. "Sorry, this class is sealed to only carry people."

FAQ

Good design doesn't require inheritance, a drone can be composed of smaller parts of a helicopter and both an EV and an ICE can be composed from common parts!

Ah yes, favor composition over inheritance.

Of course the full quote from Design Patterns: Elements of Reusable Object-Oriented Software (which popularized the whole composition over inheritance principle) is more akin to:

Ideally all reuse can be achieved by assembling existing components, but in practice inheritance is often needed to make new ones. Therefore inheritance and object composition typically work hand-in-hand.

Now that's a direct quote from Wikipedia, but I'm the one who wrote that Wikipedia entry after reading the original book, so I'll let it pass this time.

What's important to note here is that already in 1994 when the book was originally published did they acknowledge that ideally everything is composed but in practice inheritance is needed. Why? Because nobody is perfect, nobody can see the future, and nobody can predict all the possible use-cases. Miss one use-case in your seaeld class's design and your clients are going to hate you in 10 years. And this is why you simply don't seal your classes.

How to ensure nobody breaks my classes?

Don't give them push/merge permissions to your project. If they break the code on their end, that's not your problem. If I incorrectly extend Angular's components or Qt's Widgets or write an invalid extension for Firefox, did I just break their code or mine?

But the fragile base class problem!

A rare niche case where changing a base class's implementation (cross-calls between its methods) after it was extended would break the extending subclass. How about let's not completely prohibit one of the most powerful ways of extending code after a new unforeseen use-case arises on the off-chance that we ourselves change the way our class cross-calls its own methods, no?

If you need to make such fragile changes commonly, then you're doing something horribly wrong. And if you only need them once or twice over a 10 year lifespan, like a normal developer does, then you can introduce the change as major breaking change and go as far as changing the method names while at it. As a matter of fact, I have never needed to introduce a fragile base class change.

Author Of article : Mahi Read full article