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

Regards
(From mobile)

Hello Swift community,

The review of "SE-0117: Default classes to be non-subclassable publicly" begins now and runs through July 11. The proposal is available here:

        https://github.com/apple/swift-evolution/blob/master/proposals/0117-non-public-subclassable-by-default.md

Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at

        https://lists.swift.org/mailman/listinfo/swift-evolution

or, if you would like to keep your feedback private, directly to the review manager.

What goes into a review?

The goal of the review process is to improve the proposal under review through constructive criticism and contribute to the direction of Swift. When writing your review, here are some questions you might want to answer in your review:

        * What is your evaluation of the proposal?

+1. As a big proponent of API reviews for code that's going to end up being used by others, I think sealed-by-default forces authors to think about how their code might end up being used by others more so than more-permissive alternatives

Believing that joe lambda devs might think about their code more because the compiler is going to prevent certain obscure behavior from happening seems IMHO like a blattant negation of what history tells us about human nature. Given 2 choices, most of us will choose the one involving the least amount of thinking or work; and given 2 choices with different amount of responsibilities, most of use will choose the least amount of perceived individual responsibility. Psychology 101, demonstrated in many experimentations.

Doing it because the core team wants to do it has the merrit of recognizing that in the end, they hold the keyboard and should be free to write whatever they fancy, regardless of where the choir sings. Simple and clear.
Design by consensus is the worst form of design, and the Linux kernel would never have made it to where it is today if Linus had not ignored what he had to when he had to. Happens what must happen.. and there should be no need for the half baked logic that has sometimes been invoked.

. Seeing a keyword that marks a class as unsealed is a good opportunity to start a conversation in a code review.

I have honestly never seen ios devs doing that, including in large corps. Most devs I met were lone guys or small shops working on several things in parallel, with no code review and much less discussions about software design.

···

On Jul 11, 2016, at 9:43 PM, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

On Tue, Jul 5, 2016 at 4:11 PM Chris Lattner <clattner@apple.com> wrote:

Given that Swift tries to encourage the use of value types over reference types in many places, which can't be subclassed anyway, I don't think this change should be a significant burden. I'm in the process of implementing a fairly large library that's about 95% value types and 5% reference types. The reference types are more of an implementation detail than a hierarchy of types, so I would have them be final anyway. This is completely anecdotal, of course, but it's a testament IMO to how differently Swift has me thinking about the way I structure my APIs, and subclassing has been mostly replaced by protocol extensions and composition.

I'm not compelled by the arguments that we need subclassing to fix bad APIs, because that's absolutely not what subclassing is intended for. It's a hack, and it's not a cure-all—it relies on being able to override the correct methods and inject custom behavior in the first place. The argument shouldn't be "we need open subclassing or we can't fix broken APIs"; that's a false choice. It should be "we need *something* to fix broken APIs", and that "something" should be proposed and the need for it should be argued in its own right. The ability to fix a sealed broken API does have value, but it is inherently unsafe because you might be making assumptions about pre/post-conditions that the original class author didn't think about, and those assumptions could become invalid in the future (or might rely on internal implementation details that you cannot predict). Rather than abusing a construct that is not suited for that purpose, those arguing for the need for that functionality should propose something more appropriate. This would be a win-win; we'd have a clean way of expressing API boundaries, and an unsafe-but-acknowledged-as-such way of hooking into APIs if a trap door is needed. (Of course, with Swift at such a young age, it's hard to know what the needs for that are until we have some more mature libraries to present as use cases.)

        * Is the problem being addressed significant enough to warrant a change to Swift?

Yes.

        * Does this proposal fit well with the feel and direction of Swift?

Yes. The behavior that classes are unsealed within the same module but sealed by default outside the module aligns nicely with the way internal visibility already works in the language. Newcomers and app developers don't have to think about it, but those who want to release code for others to use must; I think that's the right level of responsibility.

        * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
        * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Read the proposal and followed the heated discussion in the review thread.

More information about the Swift evolution process is available at

        https://github.com/apple/swift-evolution/blob/master/process.md

Thank you,

-Chris Lattner
Review Manager

_______________________________________________
swift-evolution-announce mailing list
swift-evolution-announce@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution-announce

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

-1. I strongly oppose this proposal and think that it adds substantial
complexity to the language with introduction of yet another set of keywords
that are similar to `final` and visibility modifiers, but work differently.
The proposal doesn't cover the behaviour of `final` and having `final` and
`overridable`/`subclassable` in the language at the same time would make it
more complex and harder to learn.

···

06.07.2016 01:11 Chris Lattner via swift-evolution <
swift-evolution@swift.org>:
>
> Hello Swift community,
>
> The review of "SE-0117: Default classes to be non-subclassable publicly"
begins now and runs through July 11. The proposal is available here:
>
>
https://github.com/apple/swift-evolution/blob/master/proposals/0117-non-public-subclassable-by-default.md
>
> Reviews are an important part of the Swift evolution process. All
reviews should be sent to the swift-evolution mailing list at
>
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
> or, if you would like to keep your feedback private, directly to the
review manager.
>
> What goes into a review?
>
> The goal of the review process is to improve the proposal under review
through constructive criticism and contribute to the direction of Swift.
When writing your review, here are some questions you might want to answer
in your review:
>
> * What is your evaluation of the proposal?
> * Is the problem being addressed significant enough to warrant a
change to Swift?
> * Does this proposal fit well with the feel and direction of Swift?
> * If you have used other languages or libraries with a similar
feature, how do you feel that this proposal compares to those?
> * How much effort did you put into your review? A glance, a quick
reading, or an in-depth study?
>
> More information about the Swift evolution process is available at
>
> https://github.com/apple/swift-evolution/blob/master/process.md
>
> Thank you,
>
> -Chris Lattner
> Review Manager
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

   * What is your evaluation of the proposal?

I think it's ultimately a good idea. Being noncommittal about subclassability/overridability—and thus forbidding it in public scope, but not making any promises about what the module does internally—is the alternative that preserves the most freedom for the module, and therefore the most appropriate default.

However, I don't like the `subclassable` and `overridable` keywords. They read like opposites of `final` with no implications for access level; I could easily imagine somebody marking an internal class `subclassable` assuming that it merely means it can be subclassed internally, and being very surprised (or even not noticing!) that the class has been made public. They're also long and cumbersome; that might be seen as a positive, but I think it will increase the inevitable backlash against this change.

I prefer the keyword `open`, which sounds like it could be a statement about the item's accessibility—and even sounds like it ought to be "more public than public"—and is short enough that it ought to be difficult to grumble about the change. It also means that both classes and members use the same keyword, and gives us a keyword that we can later use to "open" other things in the language, such as allowing you to extend enums with new cases.

Agreed; I also prefer "open" to having two different long keywords that don't (at least to my ear) imply "public".

+1. I agree that the keywords in the proposal don't feel like they imply public and do feel like they might be required even internally, a really unfortunate combination.

···

Sent from my iPad

On Jul 5, 2016, at 8:53 PM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

On Jul 5, 2016, at 6:45 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

I think Kevin Lundberg is right to worry about testability, but I don't think that has to prevent this change. Instead, we should permit `@testable` imports to subclass/override things that are not publicly subclassable/overridable, and thus a module built with "Enable Testability" on can't actually assume there are no subclasses/overrides of `internal` classes/members even if it doesn't see any. This will block optimizations in debug builds, but not in release builds. The proposal should be edited to explain this `@testable` behavior.

IIUC the basic design of @testable is to treat the tests for the testable thing as existing within its module, so I think this just falls out. I agree that it should be spelled out in the proposal, though.

John.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

That makes sense to me. Please explicitly add that to the proposal, thank you!

-Chris

···

On Jul 5, 2016, at 6:53 PM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

I think Kevin Lundberg is right to worry about testability, but I don't think that has to prevent this change. Instead, we should permit `@testable` imports to subclass/override things that are not publicly subclassable/overridable, and thus a module built with "Enable Testability" on can't actually assume there are no subclasses/overrides of `internal` classes/members even if it doesn't see any. This will block optimizations in debug builds, but not in release builds. The proposal should be edited to explain this `@testable` behavior.

IIUC the basic design of @testable is to treat the tests for the testable thing as existing within its module, so I think this just falls out. I agree that it should be spelled out in the proposal, though.

I hadn't considered @testable, and it may be one way to mitigate the
trouble this could cause in tests, so thank you both for bringing it up
as the proposal should definitely account for it. I'm curious though how
this would solve the case of trying to subclass a module's class in a
test where you don't have the source? If you don't have control over the
source, you can't rebuild it to enable testability, and it might even be
desirable for someone to refuse to distribute a binary with testability
enabled if doing so might reveal proprietary information or lead to a
possible security problem with their library.

···

On 7/5/2016 9:53 PM, John McCall via swift-evolution wrote:

On Jul 5, 2016, at 6:45 PM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

  * What is your evaluation of the proposal?

I think it's ultimately a good idea. Being noncommittal about subclassability/overridability—and thus forbidding it in public scope, but not making any promises about what the module does internally—is the alternative that preserves the most freedom for the module, and therefore the most appropriate default.

However, I don't like the `subclassable` and `overridable` keywords. They read like opposites of `final` with no implications for access level; I could easily imagine somebody marking an internal class `subclassable` assuming that it merely means it can be subclassed internally, and being very surprised (or even not noticing!) that the class has been made public. They're also long and cumbersome; that might be seen as a positive, but I think it will increase the inevitable backlash against this change.

I prefer the keyword `open`, which sounds like it could be a statement about the item's accessibility—and even sounds like it ought to be "more public than public"—and is short enough that it ought to be difficult to grumble about the change. It also means that both classes and members use the same keyword, and gives us a keyword that we can later use to "open" other things in the language, such as allowing you to extend enums with new cases.

Agreed; I also prefer "open" to having two different long keywords that don't (at least to my ear) imply "public".

I think Kevin Lundberg is right to worry about testability, but I don't think that has to prevent this change. Instead, we should permit `@testable` imports to subclass/override things that are not publicly subclassable/overridable, and thus a module built with "Enable Testability" on can't actually assume there are no subclasses/overrides of `internal` classes/members even if it doesn't see any. This will block optimizations in debug builds, but not in release builds. The proposal should be edited to explain this `@testable` behavior.

IIUC the basic design of @testable is to treat the tests for the testable thing as existing within its module, so I think this just falls out. I agree that it should be spelled out in the proposal, though.

John.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Intention.

IMO, intention may lead to more secure systems (and libraries). By
having to explicitly final everything I have to choose with parts of
my class/library would be locked and have to worry and check if any
public thing could be used to exploit it or make the system work in a
way I did not intended to. Also, final will prevent anyone including
me from extending/overriding. Defaulting to final would require from
me to explicitly declare the open endpoints in my libraries, so I
could explicitly open only the ones that are really intended to be
used in that way by third-parties.

As an example, I'm working on a system which has an internal
representation of Files and Folders using a common superclass (lets
call it Entry). I would like for other developers to be able to create
new entry types (not only inheriting from File) but I do not wish for
them to extend from Folder or any of its subclasses (specialised
folders). By using final I can prevent others from extending my Folder
but I cannot extend it myself and thus need another mechanism for
achieving this behaviour without bloating the Folder class with all
its specialisations. This proposal would allow me to make my Folder
and its subclasses publicly available/usable but would prevent others
from subclassing and thus misusing them in ways I did not intend them
to. The same rationale applies to methods.

I would underline this and add that the "final" workflow doesn't work very well
for methods. You've started with a final class, but now you want to allow
subclasses, so you remove the "final"... and now you have to carefully
add it back to every method and property on your class, because the default
is non-final. And every time you modify the class in the future, you have to
remember to think about "final" for everything you add. Forbidding external
overrides is the safer default assumption.

The default is also better for programmers using the library, because the
class author's intent is much clearer. I've maintained plenty of OO code where
subclassers weren't sure how they were supposed to customize the behavior
of the superclass, and so they just overrode a ton of different methods and repeated
the same logic in every place instead of using the already-defined extension
points (or asking for a new one). Result: an unmaintainable subclass and a
superclass that can't be changed without breaking everything.

John.

···

On Jul 6, 2016, at 12:35 PM, Leonardo Pessoa via swift-evolution <swift-evolution@swift.org> wrote:

L

On 6 July 2016 at 16:09, Goffredo Marocchi <panajev@gmail.com> wrote:

Leonardo, how is defaulting to final/sealed helping you write better libraries than having a final keyword for what you need to close instead?

Sent from my iPhone

On 6 Jul 2016, at 16:48, Leonardo Pessoa via swift-evolution <swift-evolution@swift.org> wrote:

The review of "SE-0117: Default classes to be non-subclassable publicly" begins now and runs through July 11. The proposal is available here:

      https://github.com/apple/swift-evolution/blob/master/proposals/0117-non-public-subclassable-by-default.md

      * What is your evaluation of the proposal?

+1. Being able to control how a class from my libraries are going to
be used by third-parties could enable a better designed API with more
control of how it is intended to be used. I'm just not fond of using
the proposed keywords ('subclassable' and 'overridable') as they feel
more like protocol or attribute names; I'd be more inclined to use the
alternative 'public open' instead, or 'public(open)' as a second
option.

      * Is the problem being addressed significant enough to warrant a change to Swift?

I'd say it is significant to every language.

      * Does this proposal fit well with the feel and direction of Swift?

Yes.

      * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

C# uses the keyword 'virtual' to explicitly mark methods that can be
overriden (not considered in the alternatives but I'm not a big fan of
it).

      * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I've took (a small) part on the thread discussing this proposal but
followed it closely
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Removing the `final` keyword would mean there would be no way to have a class of `internal` (default) scope that subclasses and another class of `internal` (default) scope and overrides a method of `internal` (default) scope.

Scott

···

On Jul 6, 2016, at 12:50 PM, Leonardo Pessoa <me@lmpessoa.com> wrote:

Scott, you really got a point here: should this proposal pass, I
believe the final keyword should be removed as it would be already the
default behaviour and thus unnecessary. I don't think this is on the
proposal.

This proposal is specifically targeting library interfaces. It's not a slippery slope towards locking things down at a sub-library level because (1) we've already considered and rejected the analogous sub-library-level proposal (as "final by default") and (2) almost all of the justifications are tied to the specific problems that arise with library interfaces.

In general, Swift already treats library interfaces as a special point at which a lot of considerations change. The most prominent example of that is access control, but there are a lot of other examples that will become more apparent as we complete the resilience model, solidify the ABI, and start really supporting binary distribution of libraries. The basic idea is that library designers face a set of language problems that other programmers don't, and the language ought to understand that and provide a different set of features and defaults. This is a language design that's made possible by Swift's relatively strong commitment to defining and enforcing library boundaries, as opposed to the languages you list. To me, this is a great way to only get dogmatism when it's actually useful and necessary.

John.

···

On Jul 6, 2016, at 1:41 PM, Goffredo Marocchi via swift-evolution <swift-evolution@swift.org> wrote:
Sent from my iPhone

On 6 Jul 2016, at 21:22, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:

In the era of increased open sourcing, easy forking, and more community-driven development, this concern is less severe than it used to be. I rarely use any closed-sourced libraries for iOS development. If I need to tweak some library and non-subclassibility is getting in the way, then I can fork it — and perhaps even contribute my changes back to improve the upstream project. In an open source world, “closed by default” makes a lot more sense.

Maintaining a fork, realistically often without hope of upstream merging, your changes is feels like a very business unfriendly idea and less scalable than it sounds in many environments.

I see closed by default as part of the movement some people seem to be embracing of opt-out model in which freedom and versatility is forcefully restrained, making the language more complex and exotic/breaking conventions for the sake of protecting people from themselves, instead of opt-in models which require programmers to be diligent and know when to constrain themselves while enjoying more flexible defaults.
I am not asking for JavaScript, but I do not want this language to go the complete polar opposite, more dogmatic than C++ or Java.

It certainly has its problems, but in practice it’s no worse than brittle workarounds such as unintended subclassing.

In the case of forking, upgrading a library comes with the cost of merging changes. In the case of brittle subclassing, upgrading a library comes with the cost of your patches suddenly breaking. In either case, you have a body of code which is tightly coupled to an external library in ways that the library's author isn’t monitoring for breakage.

In my experience, forking is usually the less costly route because it gives more control. Modern version control makes maintaining a fork over time much easier than it used to be — and the ever-improving social dynamics of pull requests make forks less likely to live on forever.

Cheers,

Paul

···

On Jul 6, 2016, at 3:41 PM, Goffredo Marocchi <panajev@gmail.com> wrote:

On 6 Jul 2016, at 21:22, Paul Cantrell via swift-evolution <swift-evolution@swift.org> wrote:

In the era of increased open sourcing, easy forking, and more community-driven development, this concern is less severe than it used to be. I rarely use any closed-sourced libraries for iOS development. If I need to tweak some library and non-subclassibility is getting in the way, then I can fork it — and perhaps even contribute my changes back to improve the upstream project. In an open source world, “closed by default” makes a lot more sense.

Maintaining a fork, realistically often without hope of upstream merging, your changes is feels like a very business unfriendly idea and less scalable than it sounds in many environments.

Intention.

IMO, intention may lead to more secure systems (and libraries). By
having to explicitly final everything I have to choose with parts of
my class/library would be locked and have to worry and check if any
public thing could be used to exploit it or make the system work in a
way I did not intended to. Also, final will prevent anyone including
me from extending/overriding. Defaulting to final would require from
me to explicitly declare the open endpoints in my libraries, so I
could explicitly open only the ones that are really intended to be
used in that way by third-parties.

As an example, I'm working on a system which has an internal
representation of Files and Folders using a common superclass (lets
call it Entry). I would like for other developers to be able to create
new entry types (not only inheriting from File) but I do not wish for
them to extend from Folder or any of its subclasses (specialised
folders). By using final I can prevent others from extending my Folder
but I cannot extend it myself and thus need another mechanism for
achieving this behaviour without bloating the Folder class with all
its specialisations. This proposal would allow me to make my Folder
and its subclasses publicly available/usable but would prevent others
from subclassing and thus misusing them in ways I did not intend them
to. The same rationale applies to methods.

L

···

On 6 July 2016 at 16:09, Goffredo Marocchi <panajev@gmail.com> wrote:

Leonardo, how is defaulting to final/sealed helping you write better libraries than having a final keyword for what you need to close instead?

Sent from my iPhone

On 6 Jul 2016, at 16:48, Leonardo Pessoa via swift-evolution <swift-evolution@swift.org> wrote:

The review of "SE-0117: Default classes to be non-subclassable publicly" begins now and runs through July 11. The proposal is available here:

       https://github.com/apple/swift-evolution/blob/master/proposals/0117-non-public-subclassable-by-default.md

       * What is your evaluation of the proposal?

+1. Being able to control how a class from my libraries are going to
be used by third-parties could enable a better designed API with more
control of how it is intended to be used. I'm just not fond of using
the proposed keywords ('subclassable' and 'overridable') as they feel
more like protocol or attribute names; I'd be more inclined to use the
alternative 'public open' instead, or 'public(open)' as a second
option.

       * Is the problem being addressed significant enough to warrant a change to Swift?

I'd say it is significant to every language.

       * Does this proposal fit well with the feel and direction of Swift?

Yes.

       * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

C# uses the keyword 'virtual' to explicitly mark methods that can be
overriden (not considered in the alternatives but I'm not a big fan of
it).

       * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I've took (a small) part on the thread discussing this proposal but
followed it closely
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Scott, I think your writing got a bit confuse but, if I got your
intention right, since you are the owner of the class, you may choose
to subclass it or not internally, no questions asked. I need no finals
in my apps and I only subclass if I intend to. If you are in control
of your own code, why would you need to ensure there would be no
subclassing/overriding? I'm not opposed to keeping the keyword if it
is important to anyone to be sure of that for internals. As for what
is public you will gain better control of what other people do to your
classes and methods.

L

···

On 6 July 2016 at 16:56, Scott James Remnant <scott@netsplit.com> wrote:

On Jul 6, 2016, at 12:50 PM, Leonardo Pessoa <me@lmpessoa.com> wrote:

Scott, you really got a point here: should this proposal pass, I
believe the final keyword should be removed as it would be already the
default behaviour and thus unnecessary. I don't think this is on the
proposal.

Removing the `final` keyword would mean there would be no way to have a class of `internal` (default) scope that subclasses and another class of `internal` (default) scope and overrides a method of `internal` (default) scope.

Scott

Strong +1 for me, separating access control from "open-to-subclasses" is
a great feature. Leonardo's example of why final is not enough is great.

My stance is that Swift should be safe by default, predictable, and the
compiler should know enough about the code to actually help me and this
proposal fits this.

About testability, I don't think we should downplay how to test "sealed"
classes from outside the framework. I do agree that the class should be
treated as a black box with only public APIs available, but testing how
my app is using those APIs should be possible somehow.

Last but not least, I don't like the proposed subclassable/overridable,
specially because they imply public.

···

On Wed, Jul 6, 2016, at 12:35, Leonardo Pessoa via swift-evolution wrote:

Intention.

IMO, intention may lead to more secure systems (and libraries). By
having to explicitly final everything I have to choose with parts of
my class/library would be locked and have to worry and check if any
public thing could be used to exploit it or make the system work in a
way I did not intended to. Also, final will prevent anyone including
me from extending/overriding. Defaulting to final would require from
me to explicitly declare the open endpoints in my libraries, so I
could explicitly open only the ones that are really intended to be
used in that way by third-parties.

As an example, I'm working on a system which has an internal
representation of Files and Folders using a common superclass (lets
call it Entry). I would like for other developers to be able to create
new entry types (not only inheriting from File) but I do not wish for
them to extend from Folder or any of its subclasses (specialised
folders). By using final I can prevent others from extending my Folder
but I cannot extend it myself and thus need another mechanism for
achieving this behaviour without bloating the Folder class with all
its specialisations. This proposal would allow me to make my Folder
and its subclasses publicly available/usable but would prevent others
from subclassing and thus misusing them in ways I did not intend them
to. The same rationale applies to methods.

L

On 6 July 2016 at 16:09, Goffredo Marocchi <panajev@gmail.com> wrote:

Leonardo, how is defaulting to final/sealed helping you write better
libraries than having a final keyword for what you need to close
instead?

Sent from my iPhone

On 6 Jul 2016, at 16:48, Leonardo Pessoa via swift-evolution <swift- >> evolution@swift.org> wrote:

The review of "SE-0117: Default classes to be non-subclassable
publicly" begins now and runs through July 11. The proposal is
available here:

https://github.com/apple/swift-evolution/blob/master/proposals/0117-non-public-subclassable-by-default.md

      * What is your evaluation of the proposal?

+1. Being able to control how a class from my libraries are going to
be used by third-parties could enable a better designed API
with more
control of how it is intended to be used. I'm just not fond of using
the proposed keywords ('subclassable' and 'overridable') as
they feel
more like protocol or attribute names; I'd be more inclined to
use the
alternative 'public open' instead, or 'public(open)' as a second
option.

      * Is the problem being addressed significant enough to
        warrant a change to Swift?

I'd say it is significant to every language.

      * Does this proposal fit well with the feel and direction of
        Swift?

Yes.

      * If you have used other languages or libraries with a
        similar feature, how do you feel that this proposal
        compares to those?

C# uses the keyword 'virtual' to explicitly mark methods that can be
overriden (not considered in the alternatives but I'm not a big
fan of
it).

      * How much effort did you put into your review? A glance, a
        quick reading, or an in-depth study?

I've took (a small) part on the thread discussing this proposal but
followed it closely
_________________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_________________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Regards
LM
(From mobile)

* What is your evaluation of the proposal?

-1 as is. I do not want to be constrained by authors of libraries or
frameworks into interacting with a system in only the ways they forsee.
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.

Out of curiosity, what is your feeling about “internal” as the default level of access control? It seems that following your concern to its logical conclusion would lead to a design where all members of a public class would be forced to be public. After all, the author of a library or framework may not forsee the need to interact with a member that they did not explicitly mark public

Can't really help for feel like it is training wheels all around... or padlocks on every kitchen cupboards. What if this had been the philosophy from swift 0.1, what would the ecosystem look like today? (genuine question to which I do not have the answer)

···

On Jul 6, 2016, at 7:52 AM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Jul 5, 2016, at 5:54 PM, Kevin Lundberg via swift-evolution <swift-evolution@swift.org> wrote:

-Chris
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I can appreciate this argument, but I would hope that my viewpoint is a
bit more nuanced than that :). To turn the tables a bit, one could argue
that, taken to the proposal's logical conclusion, writable properties
should not be publicly writable for safety's sake. Instead, they should
be required to be explicitly marked as publicly settable if needed as it
should be up to the author of that type to carefully consider how safe
it is for others to mutate the state of their types. Yet today both
sides of a property are given the same access level unless one
explicitly restricts the visibility of it's setter. The current behavior
(of properties specifically, and the access control feature as a whole)
achieves a balance of convenience, power, and safety that I am happy with.

The proposed change however sacrifices too much convenience for a
greater sense of safety and control by default. It's not possible to
accidentally override a method like it is in java or objective-c, so the
proposal won't help people who might accidentally override something. If
a developer tries to override a method or class they probably have a
specific reason in mind for doing so, and taking away the options that
this ability presents, by nature of it being the default behavior,
doesn't sit well with me as it has the potential to take away a good
tool from my toolbox.

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

···

On 7/6/2016 1:52 AM, Chris Lattner wrote:

On Jul 5, 2016, at 5:54 PM, Kevin Lundberg via swift-evolution <swift-evolution@swift.org> wrote:

* What is your evaluation of the proposal?

-1 as is. I do not want to be constrained by authors of libraries or
frameworks into interacting with a system in only the ways they forsee.
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.

Out of curiosity, what is your feeling about “internal” as the default level of access control? It seems that following your concern to its logical conclusion would lead to a design where all members of a public class would be forced to be public. After all, the author of a library or framework may not forsee the need to interact with a member that they did not explicitly mark public.

-Chris

Regards
LM
(From mobile)

If you have a ParentClass and a SubClass, and the ParentClass is sealed while the SubClass is subclassable. What happens? No matter how this question is answered, I don't like the answer. (compile error => bad. || make it as the user wishes => bad; what do we gain by letting ParentClass remain sealed? || make ParentClass implicitly subclassable too => bad.)

I'm happy that there are not only supporters for this proposal, but imho the example is no compelling argument:
With no doubt, I'd expect I can subclass only SubClass — like I can't instantiate an abstract class, which is just fine for its children.
ParentClass might do some dangerous things that don't happen in SubClass, so there might even be a use-case (but imho it would be better if I could mark ParentClass as internal in this situation).

But imho there is another aspect I haven't read about yet:
"final by default" would have had direct impact on any developer, while this proposal merely changes things for those who create libraries…
So, the question is: How will those be build?

If you live in a world of secrets and non-disclosure, I can understand that sealed is desirable — but that's not the future I want to see, and github is a good indication that others share this opinion.

If you share the sympathy for Open source, the two scenarios are as follows:
We stick with "open by default"; users of libraries will use them in ways that the creator hasn't thought of before, and bugs will show up.
But: We know how to deal with bugs, that's our job! So in the best case, we find the reason for the bad behavior, create a pull request, and everyone is happy.

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.
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.
You can create a pull request as well, but it doesn't offer a real improvement to the author, who is already busy with dozens of similar requests by other users -> you end up with a custom branch with all the housekeeping associated with it.

So overall, I'm quite sure that the proposal won't improve software quality, but rather degrade it.

:)

···

On Jul 6, 2016, at 10:39 PM, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:

Tino
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

lol :)

···

On Thu, Jul 7, 2016 at 1:41 PM, Tino Heth via swift-evolution < swift-evolution@swift.org> wrote:

In an open source world, “closed by default” makes a lot more sense.

That sounds Orwellian to me:
War is Peace, Freedom is Slavery, Ignorance is Strength — and sealed is
open?

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

To be fair and practical with the proposal it does not remove the
ability to inherit any of the UIKit classes because all Objective-C
classes are imported as "open".

Food for thought on inheritance-is-the-only-fix, how have we worked all
these years with C libraries like Security, Foundation, Core Graphics,
GCD, and so on if C doesn't have inheritance? My point here is not to
suggest anything other than to keep an open mind, the proposal is not
removing OO from Swift. It is definitely a non conventional approach
when compared to other languages, Kotlin is the only language with
something similar but I have never used it.

I have seen a lot of problems being solved by inheritance that could be
solved by composition in a way that was more reliable, testable, and
clear. When I asked why inheritance the answer is most of the time
because that is the way they know how to do things, like it was the only
tool available. I think Swift has as opportunity to increase software
quality by providing good defaults that make developers understand what
are the consequences of their choices. Maybe I'm too optimistic.

···

On Thu, Jul 7, 2016, at 16:01, Aditya Krishnadevan via swift-evolution wrote:

I agree with everything James has to say here. Making classes non-
subclassable by default is not optimal.
A lot of fixes for small bugs in UIKit involve using a subclass that
overrides at method or slightly modified behaviour as a temporary
patch until the issue is fixed at the framework level.
Preventing this *and* introducing a new keyword simply adds to the
complexity without bringing too much to the table.

Aditya Krishnadevan.

On 06-Jul-2016, at 6:03 PM, James Campbell via swift-evolution <swift- > evolution@swift.org> wrote:

-0.5 I think preventing subclassing is a bad idea, sometimes there
are bugs which can only be resolved by subclassing and this removes a
lot of power from app makers.

On 6 July 2016 at 13:23, Jacopo Andrea Giola via swift-evolution <swift- >> evolution@swift.org> wrote:

> * What is your evaluation of the proposal?

Unless someone can prove to me why we wouldn't need this for
fixing bugs I still thing this is only a good system to hint at
the developer that they shouldn't be using this class unless they
have to.

I could envision the compiler using the overide keyword to force
the developer to acknowledge they are using a non-reccomended class
like so:

// This class implements a polyfill which fixes a bug in the
keychain class
override class PolyfillForKeychainBug: Keychain {

}

Without this the compiler would throw an error "Non-open class can't
be overridden without `override` keyword"

> * Does this proposal fit well with the feel and direction of
> Swift?

It does in terms of safety but not in terms of simplicity.

> * If you have used other languages or libraries with a
> similar feature, how do you feel that this proposal
> compares to those?

It works like Java but I never liked final

> * How much effort did you put into your review? A glance, a
> quick reading, or an in-depth study?

I’ve read the proposal

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_________________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Sent from my iPhone

Even in Java, it is a bad idea to leave classes subclassable; but having to remember to add final is a chore.

I still think it is worth doing that chore. The fact of the matter is that Java did not and is not enforcing that default and how many widely used production languages you know that do enforce this by default instead of asking library authors to do this bit of work?

People keep talking about just adding final. This *is not* an alternative. We are not talking about preventing subclasses by default (i.e. final by default).

We are talking about preventing subclasses *in other modules* by default (i.e. sealed by default). The alternative would be to introduce a sealed keyword (or similar).

There are times when you *need* to use subclasses inside your module. Some or all of them may not even be directly visible externally (class clusters). However, you *do not* want any new subclasses added as you know that is not likely to end well. This is why having sealed, not just final, is important.

By choosing sealed as a default rather than final, we are keeping the "subclassable by default" status *within* modules. This facilitates experimentation and eliminates the need for application level code to opt-in to subclassing while still making external API contracts explicit and therefore hopefully more robust. It is the default most in-line with the values and goals of Swift.

'final' and 'sealed' are two very different things. Let's please keep this focused on what is actually being proposed.

···

Sent from my iPad

On Jul 9, 2016, at 3:48 AM, Goffredo Marocchi via swift-evolution <swift-evolution@swift.org> wrote:

On 8 Jul 2016, at 15:09, Károly Lőrentey via swift-evolution <swift-evolution@swift.org> wrote:

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Ok, then I should ask you to consider what I said earlier and substitute "final by default" with "sealed by default" and if we have this sealed keyword not to make it the default.
Trust coders and people a bit more instead of resorting to more involved obligatory processes instead. Do we really need in this case to seal modules by default? Can we just have a keyword that the library author can use and express this intent explicitly?

Usually, look at some countries like Italy in a legislative sense, when you attempt to regulate in a way that everything is kind of banned except what you explicitly allow you get more convoluted, complex, and nerve wrecking solutions than allowing everything except what you explicitly ban (reviewing it all over time of course).

···

Sent from my iPhone

On 9 Jul 2016, at 13:36, Matthew Johnson <matthew@anandabits.com> wrote:

Sent from my iPad

On Jul 9, 2016, at 3:48 AM, Goffredo Marocchi via swift-evolution <swift-evolution@swift.org> wrote:

Sent from my iPhone

On 8 Jul 2016, at 15:09, Károly Lőrentey via swift-evolution <swift-evolution@swift.org> wrote:

Even in Java, it is a bad idea to leave classes subclassable; but having to remember to add final is a chore.

I still think it is worth doing that chore. The fact of the matter is that Java did not and is not enforcing that default and how many widely used production languages you know that do enforce this by default instead of asking library authors to do this bit of work?

People keep talking about just adding final. This *is not* an alternative. We are not talking about preventing subclasses by default (i.e. final by default).

We are talking about preventing subclasses *in other modules* by default (i.e. sealed by default). The alternative would be to introduce a sealed keyword (or similar).

There are times when you *need* to use subclasses inside your module. Some or all of them may not even be directly visible externally (class clusters). However, you *do not* want any new subclasses added as you know that is not likely to end well. This is why having sealed, not just final, is important.

By choosing sealed as a default rather than final, we are keeping the "subclassable by default" status *within* modules. This facilitates experimentation and eliminates the need for application level code to opt-in to subclassing while still making external API contracts explicit and therefore hopefully more robust. It is the default most in-line with the values and goals of Swift.

'final' and 'sealed' are two very different things. Let's please keep this focused on what is actually being proposed.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Hi,

However, you *do not* want any new subclasses added as you know that is not likely to end well.

Im curious, what kind of real-world scenario would "not end well" cover?

I’m genuinely curious, since Im still on the fence about this, but am willing to be convinced… if sealed by default brings more positives than negatives…

Thanks in advance.

Andre

···

2016/07/09 21:36、Matthew Johnson via swift-evolution <swift-evolution@swift.org> のメール:

Sent from my iPad

On Jul 9, 2016, at 3:48 AM, Goffredo Marocchi via swift-evolution <swift-evolution@swift.org> wrote:

Sent from my iPhone

On 8 Jul 2016, at 15:09, Károly Lőrentey via swift-evolution <swift-evolution@swift.org> wrote:

Even in Java, it is a bad idea to leave classes subclassable; but having to remember to add final is a chore.

I still think it is worth doing that chore. The fact of the matter is that Java did not and is not enforcing that default and how many widely used production languages you know that do enforce this by default instead of asking library authors to do this bit of work?

People keep talking about just adding final. This *is not* an alternative. We are not talking about preventing subclasses by default (i.e. final by default).

We are talking about preventing subclasses *in other modules* by default (i.e. sealed by default). The alternative would be to introduce a sealed keyword (or similar).

There are times when you *need* to use subclasses inside your module. Some or all of them may not even be directly visible externally (class clusters). However, you *do not* want any new subclasses added as you know that is not likely to end well. This is why having sealed, not just final, is important.

By choosing sealed as a default rather than final, we are keeping the "subclassable by default" status *within* modules. This facilitates experimentation and eliminates the need for application level code to opt-in to subclassing while still making external API contracts explicit and therefore hopefully more robust. It is the default most in-line with the values and goals of Swift.

'final' and 'sealed' are two very different things. Let's please keep this focused on what is actually being proposed.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution