The justification for this proposal is all about supporting the people who are working to design library APIs right, and about maintaining consistency with the design philosophy of Swift. To wit: in Swift, where there’s a default choice, it’s the safe one;
I challenge this claim:
Safety is valued, but Swift cares (and should care!) about pragmatism as well… the most obvious example that comes to my mind are arrays, which have no safeguards that stop you from accessing elements that aren't there.
I'm not sure I understand this point. First, a guaranteed runtime trap on an out-of-bounds index is a *massive* safety improvement over what we had in C/C++/Objective-C.
Second, safety is explicitly goal #1 for Swift; it's even more important than performance and expressiveness (although fortunately these aren't always at odds).
where there’s a consequential design decision, it’s explicit.
When there is no explicit statement about subclassiblily, it's reasonable to assume that there hasn't been a consequential design decision… but sadly, discussion like this mainly driven by dogmatism, because there is no evidence for either side.
I've made some notes of the arguments (pro and con) that I've seen in this thread and elsewhere; see them below. I think we have seen ample evidence in support for most of them, from both sides. As usual, our differences are difficult/impossible to reconcile. People may have become a bit theatrical at times, but the discussions I've read have been far from dogmatic.
Thankfully we can rely on the core team to break the stalemate. (I think it's safe to say that despite all the drama, things will turn out OK either way. Things generally do.)
I'm firmly in the +1 camp, so take my summary of the arguments against the proposal with a grain of salt. For what it's worth, I am sympathetic to most of the -1 arguments; I just find them less convincing in contrast. Some of the labels are somewhat bombastic; sorry about that.
## Arguments for SE-0117
- Doctrine: Safety is the most important design goal of Swift, and having to opt-in to cross-module subclassing has been demonstrated to be the safer choice.
- Authority: We've seen that in some OOP communities, "Explicitly design for subclassing or else prohibit it" has been a well-known and highly regarded API design advice for decades.
- Precedent: Kotlin's designers made the (admittedly questionable) decision of making final classes the default; the world didn't end. (And SE-0117 proposes a much better approach than that.) Moreover, Rust and Go are examples of popular languages that have decided to completely get rid of (implementation) inheritance; again, the sky did not fall on the heads of their designers: these languages have grown quite popular regardless of this decision. (Note though that nobody is suggesting to remove subclassing from Swift.)
- Convenience: For small-scale library developers, it becomes a little easier to create and maintain well-designed reusable Swift modules, by not having to remember to disable external subclassing whenever a new public class is created. Large-scale framework developers like Apple will remain able to do whatever they want, regardless of this proposal.
- Sensible Defaults: Accidentally leaving a class sealed can be easily fixed in a point release; accidentally leaving a class open can only be fixed by a major API version bump, because closing a class may break existing client code. (Provided that you care about strict API versioning.) So it makes sense to make the less damaging choice the default.
- Design Variety: Allowing sealed classes (either opt-in or opt-out) makes it possible to make class-hierarchies public without the burden of preparing for external subclasses. This makes certain API design patterns easier to implement in Swift. Ironically, introducing sealed classes may thus make subclassing *more* popular in carefully designed Swift packages.
- Performance: Sealing classes by default may enable the compiler to eliminate dynamic dispatch in more cases where allowing overrides was never intended. This may sometimes lead to meaningfully faster code.
- Limited Scope: Because the proposal only restricts subclassing across module boundaries, and because Swift already has a clear bias towards value types and protocol-oriented programming, and because final is already in widespread use in the language, many or most Swift users would not actually be significantly affected by this change.
- Education: The proposal gently encourages Swift users to think about ways other than subclassing to solve problems. Previous experience with the complexity of subclassing has lead to it gaining something of a bad reputation. This has made it unfashionable in the trendier section of the programming community, who are always very enthusiastic to offer advice about better approaches, and some of whom aren't even shy about showing their monads in public.
- Auditing: Some coding conventions discourage the use of subclassing in public APIs. Modules that expose APIs where the user *needs* to subclass would become easier to spot if this proposal was accepted. Programmers who're particularly pedantic and/or battle-scarred would be able to easily spot open classes and treat them as an obvious code smell.
## Arguments against SE-0117
- Pragmatism: Working around bugs by monkey patching closed-source libraries becomes even harder to pull off than it already is. An ecosystem of carefully designed and bug-free modules is a pipe dream; in the real world, packages are quickly hacked together with little if any consideration to concerns of the ivory tower people. My dependencies are full of bugs that upstream authors cannot or will not fix in time for my next release.
- Extendability: Subclassing is an important way to extend third-party classes with new functionality, and this proposal would often remove people's ability to do this. Library authors will never be able to predict all the ways their code will need to be extended. Some important classes of functionality cannot easily be added via class extensions and/or composition. Library authors should expect no right to restrict the ways their library may or may not be used and extended.
- Senseless Defaults: The design as proposed arguably provides a slight benefit to authors of well-designed libraries, but it will make subpar libraries *much* worse. Lazy library authors will leave subclassing disabled even though they might not object against subclassing at all. This will lead to a plague of one-liner pull requests to open up classes.
- Tradition: Mainstream 80s/90s-era OOP languages invariably leave classes open by default. Newcomers would be shocked to find that Swift is doing otherwise. The proposal introduces a frustrating quirk into the language with at best marginal benefits in exchange.
- Annoyance: People will need to remember to manually add an extra keyword to their public classes whenever they want to allow subclassing. People who want to always allow cross-module subclassing will always have to add the keyword. The extra work to do this would be annoying and pointless, and the proliferation of such additional keywords would make Swift needlessly wordy.
- Unit testing: The common (if messy) Objective-C / Java approach to mocking an external class by subclassing it and overriding every method becomes even more impossible in Swift. (I can't recall anyone actually making this argument, but it would've been an interesting point.)
- Incompleteness: This proposal does not go far enough; if we prefer to go in this direction, nothing less than requiring a formal description of the subclass-superclass API will do. Enabling module-external subclassing by the simple addition of a keyword would be irresponsible.
- Slippery Slope: SE-0117 adds yet another entry to the already huge list of things in Swift that subtly or openly discourage people from subclassing. How far are we from someone seriously proposing to outright rip inheritance out of the language? Enough is enough. Stop with the anti-subclassing propaganda. Implementation inheritance is a hugely important core language feature whose popularity should be preserved and whose use should be encouraged and celebrated.
- Heresy: Some people don't like programming languages that take away their freedom to do however they please. People should be trusted to use their tools well; even if they're slightly dangerous. Freedom over bureaucracy!
- The Weirdo Argument: This list represents a very curious subset of Swift developers, who are very different to the vast majority of people using Swift. Normal people just want to get their work done, and they would be infuriated if such a change would be implemented. This list is a quite exotic bubble, and it can be fatal to assume that it is representative for the mass of developers that have to deal with the consequences of its discussions. Programming languages are best evolved in a strictly democratic manner.
* * *
Sorry if I left something off, or if I misrepresented an argument. (This is a huge thread.) I had some trouble making sense of the last two or three arguments, so they're especially unlikely to represent people's actual opinions.
···
On 2016-07-11 08:42:33 +0000, Tino Heth via swift-evolution said:
--
Károly
@lorentey