[swift-evolution] Final by default for classes and methods

Dennis Lysenko dennis.s.lysenko at gmail.com
Sat Dec 19 22:22:01 CST 2015


Actually, Curt, not that I'm in favor of this proposal, but you inspired an
interesting thought--I think that if extensions were more powerful (e.g.
stored properties), then having closed classes by default might not be such
a big deal. What's the difference between using a `MyViewController`
subclass throughout your app to hack around Cocoa's limitations and writing
an extension for UIViewController to use app-wide? The only significant
difference would probably be a couple fewer hackarounds in the
UIViewController case.

Of course, it would break a lot of existing code *without a way to
automatically migrate it*. That's a deal breaker for me.

On Sat, Dec 19, 2015 at 10:09 PM Curt Clifton via swift-evolution <
swift-evolution at swift.org> wrote:

> I'm not sure how many minuses I have to give, but I'd give them all to
> this proposal.
>
> Anyone who tries to ship products on release day of Apple's operating
> system updates spends most of August and September writing horrible hacks
> so that their users are insulated from OS bugs as much as possible. All
> software has bugs, frameworks included. Please don't take away our tools
> for working around those bugs. Making classes final by default assumes a
> level of perfection on the part of framework developers that is not
> achievable.
>
> Yes, subclassing a class that wasn't designed to be subclassed has serious
> risks. Thoughtful developers sometimes take on those risks in order to
> serve their customers.
>
> Frankly, I think having `final` in the language at all is a mistake. While
> I agree that we should prefer composition to inheritance*, declaring things
> final is hubris. The only reasonable use case I've seen is for
> optimization, but that smacks of developers serving the compiler rather
> than the converse. Bringing an analog of NS_REQUIRES_SUPER to Swift would
> be most welcome; that's as far as I'd go down the path of dictating
> framework usage.
>
> Cheers,
>
> Curt
>
> *- and am thrilled with the property behaviors proposal for this use case
>
>
> On Dec 17, 2015, at 5:55 PM, Joe Groff via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>
> On Dec 17, 2015, at 5:41 PM, Rod Brown via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> My opinion is -1 on this proposal. Classes seem by design to intrinsically
> support subclassing.
>
> What if one framework provider thinks “you won’t need to subclass this
> ever” but didn’t realise your use case for doing so, and didn’t add the
> keyword? When multiple developers come at things from different angles, the
> invariable situation ends with use cases each didn’t realise. Allowing
> subclassing by default seems to mitigate this risk at least for the most
> part.
>
>
> Frameworks change, and if the framework author didn't anticipate your use
> case for subclassing, they almost certainly aren't going to anticipate it
> while evolving their implementation and will likely break your code. Robust
> subclassability requires conscious design just like all other aspects of
> API design.
>
> -Joe
>
> I think this definitely comes under the banner of “this would be nice”
> without realising the fact you’d be shooting yourself in the foot when
> someone doesn’t add the keyword in other frameworks and you’re annoyed you
> can’t add it.
>
>
> On 18 Dec 2015, at 10:46 AM, Javier Soto via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> Does it seem like there's enough interesest in this proposal? If so, what
> would be the next steps? Should I go ahead and create a PR on the evolution
> repo, describing the proposal version that Joe suggested, with classes
> closed for inheritance by default outside of a module?
>
> Thanks!
>
> On Tue, Dec 8, 2015 at 7:40 AM Matthew Johnson via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>> I understand the rationale, I just disagree with it.
>>
>> IMO adding a keyword to state your intention for inheritance is not a
>> significant obstacle to prototyping and is not artificial bookkeeping.  I
>> really don't understand how this would conflict with "consequence-free"
>> rapid development.  It is a good thing to require people to stop and think
>> before using inheritance.  Often there is a more appropriate alternative.
>>
>> The assumption that it is straightforward to fix problems within a module
>> if you later decide you made a mistake is true in some respects but not in
>> others.  It is not uncommon for apps to be monolithic rather than being
>> well factored into separate modules, with many developers contributing and
>> the team changing over time.  While this is not ideal it is reality.
>>
>> When you have the full source it is certainly *possible* to solve any
>> problem but it is often not straightforward at all.  Here is an example of
>> a real-work scenario app developers might walk into:
>>
>> 1) A class is developed without subclassing in mind by one developer.
>> 2) After the original developer is gone another developer adds some
>> subclasses without stopping to think about whether the original developer
>> designed for subclassing, thereby introducing subtle bugs into the app.
>> 3) After the second developer is gone the bugs are discovered, but by
>> this time there are nontrivial dependencies on the subclasses.
>> 4) A third developer who probably has little or no context for the
>> decisions made by previous developers is tasked with fixing the bugs.
>>
>> This can be quite a knot to untangle, especially if there are problems
>> modifying the superclass to properly support the subclasses (maybe this
>> breaks the contract the superclass has with its original clients).
>>
>> It may have been possible to avoid the whole mess if the second developer
>> was required to add 'inheritable' and 'overrideable' keywords or similar.
>> They are already required to revisit the source of it while adding the
>> keywords which may lead to consideration of whether the implementation is
>> sufficient to support inheritance in their currently intended manner.
>>
>> Implementation inheritance is a blunt tool that often leads to
>> unanticipated problems.  IMO a modern language should steer developers away
>> from it and strive to reduce the cases where it is necessary or more
>> convenient.  Making final the default would help to do this.
>>
>> Supporting sealed classes and methods that can only be subclassed or
>> overridden within the same module is not in conflict with final by
>> default.  Both are good ideas IMO and I would like to see both in Swift.
>>
>> I hope the core team is willing to revisit this decision with community
>> input.  If not I will let it go, although I doubt I will ever agree with
>> the current decision.
>>
>> Matthew
>>
>> Sent from my iPad
>>
>> On Dec 7, 2015, at 10:30 PM, John McCall <rjmccall at apple.com> wrote:
>>
>> >>> On Dec 7, 2015, at 7:18 PM, Matthew Johnson via swift-evolution <
>> swift-evolution at swift.org> wrote:
>> >>> Defaults of public sealed/final classes and final methods on a class
>> by default are a tougher call. Either way you may have design issues go
>> unnoticed until someone needs to subclass to get the behavior they want. So
>> when you reach that point, should the system error on the side of rigid
>> safety or dangerous flexibility?
>> >>
>> >> This is a nice summary of the tradeoff.  I strongly prefer safety
>> myself and I believe the preference for safety fits well with the overall
>> direction of Swift.  If a library author discovers a design oversight and
>> later decides they should have allowed for additional flexibility it is
>> straightforward to allow for this without breaking existing client code.
>> >>
>> >> Many of the examples cited in argument against final by default have
>> to do with working around library or framework bugs.  I understand the
>> motivation to preserve this flexibility bur don't believe bug workarounds
>> are a good way to make language design decisions. I also believe use of
>> subclasses and overrides in ways the library author may not have intended
>> to is a fragile technique that is likely to eventually cause as many
>> problems as it solves.  I have been programming a long time and have never
>> run into a case where this technique was the only way or even the best way
>> to accomplish the task at hand.
>> >>
>> >> One additional motivation for making final the default that has not
>> been discussed yet is the drive towards making Swift a protocol oriented
>> language.  IMO protocols should be the first tool considered when dynamic
>> polymorphism is necessary.  Inheritance should be reserved for cases where
>> other approaches won't work (and we should seek to reduce the number of
>> problems where that is the case).  Making final the default for classes and
>> methods would provide a subtle (or maybe not so subtle) hint in this
>> direction.
>> >>
>> >> I know the Swift team at Apple put a lot of thought into the defaults
>> in Swift.  I agree with most of them.  Enabling subclassing and overriding
>> by default is the one case where I think a significant mistake was made.
>> >
>> > Our current intent is that public subclassing and overriding will be
>> locked down by default, but internal subclassing and overriding will not
>> be.  I believe that this strikes the right balance, and moreover that it is
>> consistent with the general language approach to code evolution, which is
>> to promote “consequence-free” rapid development by:
>> >
>> >  (1) avoiding artificial bookkeeping obstacles while you’re hacking up
>> the initial implementation of a module, but
>> >
>> >  (2) not letting that initial implementation make implicit source and
>> binary compatibility promises to code outside of the module and
>> >
>> >  (3) providing good language tools for incrementally building those
>> initial prototype interfaces into stronger internal abstractions.
>> >
>> > All the hard limitations in the defaults are tied to the module
>> boundary because we assume that it’s straightforward to fix any problems
>> within the module if/when you decided you made a mistake earlier.
>> >
>> > So, okay, a class is subclassable by default, and it wasn’t really
>> designed for that, and now there are subclasses in the module which are
>> causing problems.  As long as nobody's changed the default (which they
>> could have done carelessly in either case, but are much less likely to do
>> if it’s only necessary to make an external subclass), all of those
>> subclasses will still be within the module, and you still have free rein to
>> correct that initial design mistake.
>> >
>> > John.
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
> --
> Javier Soto  _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>  _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151220/c4822c16/attachment.html>


More information about the swift-evolution mailing list