Swift Proposal for Default Final
Curt Clifton (tweet, comments):
That is, the suggestion is that subclassing classes and overriding methods should be implicitly banned unless the framework author takes specific action to permit such indignities. The idea has evolved a bit over the last two+ weeks, to suggest that this implicit ban only apply across module boundaries.
I was shocked to find many members of the Swift team at Apple agreeing with this suggestion. When I’d mentioned the suggestion to co-workers and to friends in the app development community, to a person they said it was ridiculous.
I can’t prove any causation, but I would certainly argue that the dynamic nature and possible overridability of even things that Apple doesn’t specifically intend to allow overriding is one of the primary reasons why AppKit has survived for 20+ years and spawned arguably the most successful application framework in history in UIKit. On the other hand, efficiency and safety have rarely been major issues.
TLDR: I don’t think using the design trade-offs of Array (which is, after all, a value type and can’t be subclassed anyway) inside stdlib, can be very usefully broadened to apply to reference types in application frameworks.
Supporting arbitrary code injection into someone else’s framework is a non-goal for Swift, perhaps even an anti-goal. […] If you replace a method on someone else’s class, you don’t actually know what semantics they’re relying on. Of course Apple code will have bugs in it. Trying to patch over these bugs in your own code is (1) obviously not an answer Apple would support, but also (2) fraught with peril, and (3) likely to break in the next OS release.
Presumably a goal for Swift is that application developers will use it to build user-facing apps for Apple’s platforms. And presumably a goal for Apple is that developers help promote Apple’s platforms by shipping apps that take advantage of the new OS features when they ship. I fear that you and others dramatically underestimate the difficultly of doing that. I acknowledge your three points. But understand that we are professionals trying to serve our mutual customers. Temporary hacks in the service of shipping is the nature of the business.
I don’t know how to make the case more strongly than I already have. This thread makes me worry that the team does not understand what it’s like for third party developers trying to serve our mutual customers.
But if you’re working on a consumer app, I do think that it’s logical vtable dispatch is what you want most of the time. So in my experience, functions need to be virtual more often than not, and the C++ code I’ve seen would be shorter if you had to explicitly mark methods as nonvirtual rather than virtual.
swizzling and aggressive subclassing are last resorts, but they are necessary in the current ecosystem.
We regularly ship multiple major products on OS release day. We know this stuff.
I could not agree with Clifton more strongly. It seems like there is a culture clash between the compiler developers, who want to increase the potential for optimization, and the app developers, who like things to be more flexible because they are building on top of an imperfect platform. Since Swift’s introduction, I have been arguing that message passing (i.e. the dynamic
keyword) should be the default, rather than vtable dispatch. The idea of locking things down further, with final
as the default, is insane.
Making code that is not the bottleneck faster is a small win compared with an increase in bugs that directly affect customers. Rose and Joe Groff are right that there are problems with patching. But if it’s temporary and done responsibly, it’s a good pragmatic solution. Bugs are inevitable, and sometimes it is months or years before they are fixed, so Apple should not stand in the way of people trying to mitigate them.
It is a disturbing thought, but it’ll be a long time before frameworks are written in Swift.
I like Swift. It’s exciting to think of future frameworks that take full advantage of it. It’s scary, and ironic, to think about how this modern, safe language may actually lead to more brittle software.
Update (2015-12-22): Brent Royal-Gordon:
This means doing some dangerous overriding, yes. But a UI that breaks after an iOS upgrade is not nearly as dangerous to my business as a three-month delay while I reimplement half of UIKit because someone in Cupertino thought they knew what I need better than I do and turned off—or even worse, left turned off without a single thought—subclassing of UIBarButtonItem.
The bottom line is this: Your users like Swift’s strictures when they’re helpful. This stricture is not helpful. Library users don’t accidentally subclass things, and with the
override
keyword in Swift, they don’t accidentally override them either. And where it truly is important, for safety or for speed, to prevent subclassing, we already havefinal
. Making it the default is less safety than suffering.
My concern when I saw Swift was that it was done by compiler guys who don’t ship or maintain apps.
Final by default requires a lvl of transparency and perfection that Apple framework engineers cannot realistically provide
Update (2015-12-23): Curt Clifton and Drew Crawford suggest middleware as a possible solution.
Update (2016-01-08): See also: Accidental Tech Podcast.
Update (2016-01-09): Friedrich Markgraf:
Apple making framework bugs unfixable was my number one concern when Swift was announced.
Subclassing a type not intended for it may be unfortunate, it may be necessary/desirable. Either way it is fixable.
Not being able to subclass a class is not.
And when the new release comes there is time for 3rd parties to fix. This is different from not being able to fix.