To start with, I am unabashedly in favor of the revised SE-0117 “Allow distinguishing between public access and public overridability”, colloquially known as “sealed-by-default.” Designing an interface to be overridden inarguably takes extra care and documentation.
Michael Tsai has collected a number of arguments against (and some for) this proposal. Some of these arguments so off-base I can’t stay silent about them. Here’s a selection:
In general, language design should not be decided by the possible existence of buggy code. However much we strive to make perfect code, there will always be bugs. (Benjamin Mayo)
Um. This is one of the primary factors a language’s design must take into account. Here are some other things this statement can be used to argue:
- Optionals are unnecessary and annoying boilerplate
- ARC or garbage collection aim to eliminate bugs, but they are opaque and there are corner cases the programmer has to know about; therefore memory should be manually managed
- Undefined behavior is nothing to worry about
- Statically-checked type systems are too annoying to bother with
The more our tooling reduces the set of bugs it’s possible to write, the fewer bugs will be written.
Apple: … We don’t particularly care if your app is broken for months or years while waiting for a bug to be fixed. (Michael Tsai)
I don’t recall the Swift team writing anything that even implies this.
By making the default be non-subclassable, if a designer does not put thought into all the ways a class can be used then I as a consumer of the library am penalized. (Kevin Lundberg)
If the library design hasn’t considered your use case, you’ve already lost. Even if you can hack the library into (seemingly) doing what you want, you have no guarantee that your solution works in all cases, or that it will continue to work in future versions of the library.
Another point I can think of is mocking in tests. I’m unaware of any fully featured mocking solution in swift, and subclassing a class to override methods for mocking purposes is one way to make unit tests work with third party dependencies. If a class was not designed for subclassing, then writing tests where the class’s behavior needs to be suppressed would not be possible. (Kevin Lundberg)
- Don’t test code you don’t own.
- Don’t mock what you don’t own.
- Use protocols and dependency injection if you’re designing an interface where you want to inject a mock for tests.
- Additional reading: Mocking Classes You Don’t Own
Can’t really help for feel like it is training wheels all around… or padlocks on every kitchen cupboards. (L. Mihalkovic)
Again, one job of a programming language is to keep sharp edges away from you.
I agree that API authors should have the power to restrict this dimension of a type’s usage, but I feel that it should be a conscious choice to do so. (Kevin Lundberg)
Library developers who are conscious enough to restrict this dimension of a class’s usage are also conscious enough to allow for subclassing where needed.
Those who aren’t, aren’t likely to write code you can subclass safely or provide the guarantee your subclasses will continue to work in the future. Sealed-by-default therefore protects you from those unconscious library developers, and doesn’t harm your ability to extend well-designed libraries.
I think it’s a step backwards. […] It’s not bad to allow sealing of classes. I don’t see real value in it though. And “sealed” should not be the default. (Michael Peternell)
I think it’s a step forwards. I see real value in it, and “sealed” should be the default.
(In other words, this is an opinion, not a technical argument.)
With “sealed by default”, the situation changes: Users are protected from some simple bugs, but nonetheless, they’ll encounter situations where the library doesn’t do exactly what they want. So, you take a look at the source, find the problem, and fix it.
This assumes that (a) all bugs caused by subclassing something that wasn’t designed to be subclassed are simple, which is false; and (b) that you can see the source of that library in order to fix a bug safely, which is not always true.
So we’re 0 for 2 on this argument so far. Let’s continue.
It’s no bug at all, it’s just a tiny degree of freedom that is missing because it wasn’t important to the author.
Okay, so now in addition to the two assumptions above we’re assuming this is a tiny change that can be made safely and easily. Fine. But let’s recognize that this is not true of all bugs, and combined with the first two assumptions this is an argument about a fairly narrow use case.
[…] So overall, I’m quite sure that the proposal won’t improve software quality, but rather degrade it.
Overall, I’m quite sure that the proposal will improve software quality, particularly over the long run.
(In other words, this is an opinion, not a technical argument.)
Thirdly, this is a huge breaking change. Not only is it a breaking change, but for a lot of people, the breakages will be outside of their control. (Jeremy Pereira)
Yes. Swift is a young language, and its development team hasn’t yet promised there will be no breaking changes.
There are IMO no advantages to sealing by default.
(This is an opinion, not a technical argument.)
If there were, I cannot imagine how they can have so consistently eluded the designers and maintainers of so many great OOD languages in the last 30 years.
Programming language design continues to be an active area of research and development, informed by experience and CS theory. “OOP has been this way for a while” is not itself a good argument; if it were, we’d probably be writing iOS apps in Lisp.
(I will leave it to someone else to point out that many of the new & advanced parts of Swift are actually the outcome of 30-year old CS research.)
… at the end of the day Swift isn’t an academic exercise, it is a real world programming language, … (Jon Akhtar)
In arguments against various Swift design decisions, many people like to make a distinction between “academic exercises” and “the real world.”
Where, exactly, do you think any of our programming paradigms or design principles came from? (Hint: OOP originated in academia.)
This is why you don’t let compiler engineers control the fate of your computing platform(s) (Ilja A. Iwas)
… boy, do I have some bad news for you.
My outsider’s perspective of Swift: X can be misused, so we’re banning X.
Seems like coding with safety scissors. (Paul Haddad)
Again, modern programming languages are designed to eliminate classes of bugs. Otherwise we’d still be writing GUI apps in plain old C, with manual memory management and gobs of undefined behaviors.
I think this is one of the worst decisions in the history of language design. (McCloud)
Okay, I’m bored now. Carry on.