[swift-evolution] [Review] SE-0117: Default classes to be non-subclassable publicly

John McCall rjmccall at apple.com
Fri Jul 8 12:23:46 CDT 2016

> On Jul 7, 2016, at 4:16 PM, Goffredo Marocchi <panajev at gmail.com> wrote:
> On Thu, Jul 7, 2016 at 11:15 PM, John McCall <rjmccall at apple.com <mailto:rjmccall at apple.com>> wrote:
> n Jul 7, 2016, at 9:39 AM, Goffredo Marocchi via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> I disagree that a stable for over 30 years of every OOP language that I know is equivalent to lack of care for good library design, but if we want to push value types by making working with classes harder so be it :P. 
> Making classes harder to work with is not a specific goal, no. :)

(Goffredo accidentally responded to me privately.  With his permission, I'm reposting our brief side-conversation to the list.)

> Is it just a "sweet oh so sweet" side-effect ;)?

Believe it or not, we do not actually have anything against classes! :)
> I don't expect that this will be a significant burden for most Swift programmers.  Mainly, that's because this only affects classes that are exposed outside of a module, and the great majority of non-system classes in a typical Cocoa program are single-purpose leaf classes that — at most — expose a few methods to other subsystems.  Swift doesn't really encourage you write complex classes that are primarily customized with subclassing; it encourages the heavy use of value types, and it encourages customization through protocols and functions.  In fact, that's not really new to Swift, it's a general lesson from the last few decades of software development: composing smaller, independent systems through well-defined interfaces leads to better software than building monolithic systems whose behavior can only be defined in reference to the whole.
> I sympathize with the argument about wanting to fix bugs and add features via override, but that's never been maintainable in the long term; you always just end up with superclasses that everyone is terrified to touch because every subclass has its own invasive "fixes", and that's even when working within a single codebase.  With libraries, you can pretty quickly get locked in to a specific version because your customizations don't work with new releases; either that, or the maintainer just decides that they can't fix of their mistakes and so goes off to rewrite it from scratch.  Either way, it's not good for the ecosystem.
> Plus, as others have mentioned, Swift already provides a lot of features that don't allow overriding: structs, final, etc.  You simply cannot rely on overriding to fix upstream bugs the way that you can in most traditional OO languages because not enough code flows through calls to overridable methods.  We should not compromise the goal of promoting stronger and more maintainable library designs just to maintain this illusion.
> John.
> Thank you for taking the time to write out this detailed defense of your position. I appreciate it a lot :)!
> I think that the issue, as evidenced in this thread too, is that library authors belief that sealing by default will bring ease of use AND a lot more safety at the same time while I fear this may make the language more complex actually.

I'm not going to deny that making classes non-subclassable by default outside of their module adds some complexity.  However, that additional complexity is subject to "progressive disclosure": it only matters to people making classes part of their public interface, and only when they actually want to allow subclasses.  Moreover, if they do want to allow subclasses, they'll try it and immediately run into the compiler error, which they can look up and hopefully find some good documentation on how to think about designing a class for subclassing.  That's a pretty gentle prod.

> I tend to prefer opt-in strategies, giving coders/people a better/safer alternative and allowing them to choose it instead of trying to babyproof everything/protect coders from themselves leaving them few ways to move out of the compiler imposed restrictions. It is easier and more scalable to figure out what to ban than what to allow (and assume everything we do not think of in advance is bad and ought to be banned)... but now I am going too much off a tangent... sorry. 

This could easily be an argument for public-by-default.  After all, internal-by-default is just protecting programmers from a mistake.  Some libraries end up with "public" written absolutely everywhere, which seems silly and unnecessary.  The rule promotes hiding a lot things from the user, but maybe those things would actually be really useful if they were exposed.  Aren't we just babying the programmer?  Is this restriction really worth anything?  Maybe it would be easier to just make everything public by default and require programmers to explicitly hide everything they want to protect.

And you know, that's not a completely unreasonable way to approach some kinds of programming.  If you're rapidly spinning up a prototype, you should not be obsessing about its software architecture, as long as you leave yourself room to think about it later (like, you know, when someone else starts depending on you).  But the thing is, the things that work well when you're hacking on a demo are not the things that work well when you're designing an API that you hope to be supporting for a while.  You really should be explicit about the things you want to expose to your clients.  You really should think carefully about the places you want to allow code injection.  And it makes sense for the language to flip some of its rules around at that library boundary to reflect the very different nature of the work.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160708/8c739da0/attachment.html>

More information about the swift-evolution mailing list