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

Regards
(From mobile)

Personally, Im not against sealed by default, but I think there are cases where closed source libraries have certain cases where workarounds are necessary, and just sealing by default will prevent those cases.

One could say, "well just use an open source one, or change vendors" but its not that easy in The Real World™ where we get certain SDKs shoved down our throats by the suits… and while that may be a separate issue to the one at hand, its still a problem that won’t resolve itself by simply locking down things…

In my own case, Ive fought with NSBrowser / NSTreeController in the past and the only way to resolve things was to subclass (and no, waiting 1 or 2 years for a fix is not acceptable if you already have a product in the wild).

So I am reticent to support this proposal without an escape hatch for those cases…

Are you concerned about closed-source vendor frameworks beyond Apple’s? Some things to consider:

1. This proposal should not impact any existing libraries - nobody should be shipping closed-source binary libraries written in Swift yet.

2. Apple’s frameworks will probably remain in Objective-C for some time to come. If / when they are replaced with Swift frameworks the default will have little (if any) impact on the public API contract. It is reasonable to expect that Apple will review the public contracts carefully and add any annotations necessary to achieve the desired semantics.

3. In the future, if you depend on any 3rd party closed-source libraries written in Swift you will be able to ship an update to your app that contains an updated / fixed version of the library independent of the user upgrading their OS.

This leaves the scenario of a case where you depend on a 3rd party, closed-source library written in Swift and where you cannot get (or use) a fix from the vendor for some reason. This is a legitimate concern, but IMO it is not large enough to outweigh all of the advantages of making sealed the default.

There is no doubt that adopting sealed by default will place some pressure on the Swift ecosystem. As others have noted, this pressure already exists in the form of value types, protocol-oriented designs, etc - the current proposal is a relatively modest increase in that pressure. I believe the pressure will have a very positive impact over time (the eventual outcome remains to be seen of course).

Swift library vendors will need to choose between opening their source, providing responsive support and bug fixes, explicitly providing the escape hatch you mention (by designing with open types) or getting a bad reputation among users.

There are IMO no advantages to sealing by default. If there were, I cannot imagine how they can have so consistently eluded the designers and maintainers of so many great OOD languages in the last 30 years. Does it mean it is just a matter of time for the core team to take it the c++ standardization committee to make sure C++ gets enhanced the same way?

···

On Jul 9, 2016, at 4:30 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Jul 9, 2016, at 8:39 AM, Andre <pyunpyun@me.com> wrote:

-Matthew

Andre

2016/07/09 22:11、Shawn Erickson <shawnce@gmail.com> のメール:

What I don't get in the arguments against this capability is the fact that many constructs in Swift can't be subclassed. Are we going to prevent library developers from presenting those in the public API? Your ability to subclass things when not supported by the library developer is already going to be greatly reduced. Additionally you are going to miss potentially helpful optimization in side the model if the library developer can't prevent extras subclassing.

It seems perfectly reasonable to allow a lot of freedoms for a library developer when designing their code on their side of the library API and not force them to expose unwanted API just because of internal design desires.

(I have myself have already struggled with having to leak what I consider internal details outside of modules we have developed internally, likely need to get around to outlining the additional issues I see)

In the end if the library isn't good and you don't like the API find one that works the way you need (or make one). I expect a fairly rich environment of libraries that will sort itself out over time.

-Shawn

On Sat, Jul 9, 2016 at 8:43 AM Andre via swift-evolution <swift-evolution@swift.org> wrote:
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

_______________________________________________
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

Forking is desirable if your goals, needs, values, etc are substantially different than the library author such that you do not agree on what the API contract should look like.

That's desirable in the same sense as an amputation that saves you from a deadly sepsis... I'd rather stay away from both situations.
Forking drains manpower from real improvements, and the same is true for trivial pull-requests that can be avoided in the first place by keeping the defaults as they are.

Regards
(From mobile)

Personally, Im not against sealed by default, but I think there are cases where closed source libraries have certain cases where workarounds are necessary, and just sealing by default will prevent those cases.

One could say, "well just use an open source one, or change vendors" but its not that easy in The Real World™ where we get certain SDKs shoved down our throats by the suits… and while that may be a separate issue to the one at hand, its still a problem that won’t resolve itself by simply locking down things…

In my own case, Ive fought with NSBrowser / NSTreeController in the past and the only way to resolve things was to subclass (and no, waiting 1 or 2 years for a fix is not acceptable if you already have a product in the wild).

So I am reticent to support this proposal without an escape hatch for those cases…

Are you concerned about closed-source vendor frameworks beyond Apple’s? Some things to consider:

1. This proposal should not impact any existing libraries - nobody should be shipping closed-source binary libraries written in Swift yet.

2. Apple’s frameworks will probably remain in Objective-C for some time to come. If / when they are replaced with Swift frameworks the default will have little (if any) impact on the public API contract. It is reasonable to expect that Apple will review the public contracts carefully and add any annotations necessary to achieve the desired semantics.

3. In the future, if you depend on any 3rd party closed-source libraries written in Swift you will be able to ship an update to your app that contains an updated / fixed version of the library independent of the user upgrading their OS.

This leaves the scenario of a case where you depend on a 3rd party, closed-source library written in Swift and where you cannot get (or use) a fix from the vendor for some reason. This is a legitimate concern, but IMO it is not large enough to outweigh all of the advantages of making sealed the default.

There is no doubt that adopting sealed by default will place some pressure on the Swift ecosystem. As others have noted, this pressure already exists in the form of value types, protocol-oriented designs, etc - the current proposal is a relatively modest increase in that pressure. I believe the pressure will have a very positive impact over time (the eventual outcome remains to be seen of course).

Swift library vendors will need to choose between opening their source, providing responsive support and bug fixes, explicitly providing the escape hatch you mention (by designing with open types) or getting a bad reputation among users.

There are IMO no advantages to sealing by default. If there were, I cannot imagine how they can have so consistently eluded the designers and maintainers of so many great OOD languages in the last 30 years. Does it mean it is just a matter of time for the core team to take it the c++ standardization committee to make sure C++ gets enhanced the same way?

You can’t compare Swift to C++ here. C++ uses « final » method and static dispatch by default, so subclassing does not imply the same fragility than with a fully dynamic language.

···

Le 9 juil. 2016 à 18:22, L. Mihalkovic via swift-evolution <swift-evolution@swift.org> a écrit :
On Jul 9, 2016, at 4:30 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jul 9, 2016, at 8:39 AM, Andre <pyunpyun@me.com <mailto:pyunpyun@me.com>> wrote:

-Matthew

Andre

2016/07/09 22:11、Shawn Erickson <shawnce@gmail.com <mailto:shawnce@gmail.com>> のメール:

What I don't get in the arguments against this capability is the fact that many constructs in Swift can't be subclassed. Are we going to prevent library developers from presenting those in the public API? Your ability to subclass things when not supported by the library developer is already going to be greatly reduced. Additionally you are going to miss potentially helpful optimization in side the model if the library developer can't prevent extras subclassing.

It seems perfectly reasonable to allow a lot of freedoms for a library developer when designing their code on their side of the library API and not force them to expose unwanted API just because of internal design desires.

(I have myself have already struggled with having to leak what I consider internal details outside of modules we have developed internally, likely need to get around to outlining the additional issues I see)

In the end if the library isn't good and you don't like the API find one that works the way you need (or make one). I expect a fairly rich environment of libraries that will sort itself out over time.

-Shawn
On Sat, Jul 9, 2016 at 8:43 AM Andre via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
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 <mailto: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 <mailto: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 <mailto: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 <mailto:swift-evolution@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution

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

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

I have been following the discussion and reading the arguments in favor and against. I think I understand both sides better now.

If this proposal is accepted I hope some more thought is given to the naming.

I would like to echo what others have said regarding the names. In particular I am still not sure about subclassable and overridable implying public. I think it would be more clear to to read "public subclassable class C".

I have these thoughts regarding the naming:

I think that subclassable could be implied when the class contains an overridable method or property. In other words, does it make sense to have an overridable method or property when the class is not subclassable? Oh, I just realized that it is more clear if it is expressed explicitly. It could also avoid making the mistake of making a class subclassable by accident.

Also "subclassable class" sounds a bit redundant. In other words, I think subclassable implies it is a class. But I am not sure I would want to leave out the class part, which brings me to one of the other alternatives:

public open class C
public open func / var

The pros here are that is is more concise. The public part could be left out because open seems to imply public. Open also suggests that it may be subclassable/ overridable. On the other hand subclassable/ overridable are both very clear though.

Thanks

···

On Jul 9, 2016, at 12:29 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Jul 9, 2016, at 11:04 AM, Tino Heth <2th@gmx.de> wrote:

Of course it can be done either way. But there are significant ecosystem robustness advantages to making sealed the default and comparatively few downsides. Most libraries are open source (so can be modified directly or via PR if necessary)

First:
The claim about robustness sounds like a fact, despite being just an opinion (feel free to correct me if you have any evidence at all). We should stay honest with our predictions.
Second:
Do you really believe there will be positive impact on open-source libraries?
My forecast is that closed by default will dramatically increase trivial pull request where developers ask for unsealing so that they can do as they like…

I think this is a good thing. It will force a considered answer and a discussion about whether or not subclassing should be supported by the library.

and I've no idea why somebody could come up with the idea that forking is desirable.

Forking is desirable if your goals, needs, values, etc are substantially different than the library author such that you do not agree on what the API contract should look like.

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

Yes, I know it'd all be the epitome of annoying boilerplate code, but my point is that if someone wants to subclass something of yours, there's really not much you can do to stop them.

This would be fine: inheritance bad, composition good ;-)

The problems of this attitude just aren't visible now, because it isn't imposed on you.

Regards
(From mobile)

Regards
(From mobile)

Personally, Im not against sealed by default, but I think there are cases where closed source libraries have certain cases where workarounds are necessary, and just sealing by default will prevent those cases.

One could say, "well just use an open source one, or change vendors" but its not that easy in The Real World™ where we get certain SDKs shoved down our throats by the suits… and while that may be a separate issue to the one at hand, its still a problem that won’t resolve itself by simply locking down things…

In my own case, Ive fought with NSBrowser / NSTreeController in the past and the only way to resolve things was to subclass (and no, waiting 1 or 2 years for a fix is not acceptable if you already have a product in the wild).

So I am reticent to support this proposal without an escape hatch for those cases…

Are you concerned about closed-source vendor frameworks beyond Apple’s? Some things to consider:

1. This proposal should not impact any existing libraries - nobody should be shipping closed-source binary libraries written in Swift yet.

2. Apple’s frameworks will probably remain in Objective-C for some time to come. If / when they are replaced with Swift frameworks the default will have little (if any) impact on the public API contract. It is reasonable to expect that Apple will review the public contracts carefully and add any annotations necessary to achieve the desired semantics.

3. In the future, if you depend on any 3rd party closed-source libraries written in Swift you will be able to ship an update to your app that contains an updated / fixed version of the library independent of the user upgrading their OS.

This leaves the scenario of a case where you depend on a 3rd party, closed-source library written in Swift and where you cannot get (or use) a fix from the vendor for some reason. This is a legitimate concern, but IMO it is not large enough to outweigh all of the advantages of making sealed the default.

There is no doubt that adopting sealed by default will place some pressure on the Swift ecosystem. As others have noted, this pressure already exists in the form of value types, protocol-oriented designs, etc - the current proposal is a relatively modest increase in that pressure. I believe the pressure will have a very positive impact over time (the eventual outcome remains to be seen of course).

Swift library vendors will need to choose between opening their source, providing responsive support and bug fixes, explicitly providing the escape hatch you mention (by designing with open types) or getting a bad reputation among users.

There are IMO no advantages to sealing by default. If there were, I cannot imagine how they can have so consistently eluded the designers and maintainers of so many great OOD languages in the last 30 years. Does it mean it is just a matter of time for the core team to take it the c++ standardization committee to make sure C++ gets enhanced the same way?

You can’t compare Swift to C++ here. C++ uses « final » method and static dispatch by default, so subclassing does not imply the same fragility than with a fully dynamic language.

... and whole module optimization does final inferrance on anything internal... so how much more training wheels do we need to write decent code? After 30 years of Objc's msg dispatching being touted as not a performance problem, all we hear for the last couple WWDC (did you pay attention to the 'they are getting it' during one of the session) is how much every single dynamic dispatch must be chased out of our systems, culminating with this 'seal by default is best for you'. Why can't developers writting code be made responsible for writing well or not?

···

On Jul 9, 2016, at 7:06 PM, Jean-Daniel Dupas <mailing@xenonium.com> wrote:

Le 9 juil. 2016 à 18:22, L. Mihalkovic via swift-evolution <swift-evolution@swift.org> a écrit :

On Jul 9, 2016, at 4:30 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

On Jul 9, 2016, at 8:39 AM, Andre <pyunpyun@me.com> wrote:

-Matthew

Andre

2016/07/09 22:11、Shawn Erickson <shawnce@gmail.com> のメール:

What I don't get in the arguments against this capability is the fact that many constructs in Swift can't be subclassed. Are we going to prevent library developers from presenting those in the public API? Your ability to subclass things when not supported by the library developer is already going to be greatly reduced. Additionally you are going to miss potentially helpful optimization in side the model if the library developer can't prevent extras subclassing.

It seems perfectly reasonable to allow a lot of freedoms for a library developer when designing their code on their side of the library API and not force them to expose unwanted API just because of internal design desires.

(I have myself have already struggled with having to leak what I consider internal details outside of modules we have developed internally, likely need to get around to outlining the additional issues I see)

In the end if the library isn't good and you don't like the API find one that works the way you need (or make one). I expect a fairly rich environment of libraries that will sort itself out over time.

-Shawn

On Sat, Jul 9, 2016 at 8:43 AM Andre via swift-evolution <swift-evolution@swift.org> wrote:
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

_______________________________________________
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

Of course it can be done either way. But there are significant ecosystem robustness advantages to making sealed the default and comparatively few downsides. Most libraries are open source (so can be modified directly or via PR if necessary)

First:
The claim about robustness sounds like a fact, despite being just an opinion (feel free to correct me if you have any evidence at all). We should stay honest with our predictions.

It has been standard advice in the Java community for at least 15 years to always prohibit external subclassing unless the class has been designed and documented to be safely subclassable, precisely because of the numerous problems that are caused by unforeseen subclassing.

Second:
Do you really believe there will be positive impact on open-source libraries?
My forecast is that closed by default will dramatically increase trivial pull request where developers ask for unsealing so that they can do as they like… and I've no idea why somebody could come up with the idea that forking is desirable.

I may be unusually careful in my API design, but I don't see how opening a class to inheritance could ever be a trivial pull request.

Enabling open subclassing involves the creation of customization hooks: a formal list of methods that subclasses are allowed to override to modify the behavior of the superclass. These methods need to be designed and their override requirements precisely documented.

Inheritance breaks encapsulation, making the API contract a lot more complicated to describe, understand and verify. The public API becomes tainted with implementation details that were previously private: for example, the exact sequence of overridable methods called by each public function becomes de facto part of the public interface. Adding/reordering/removing calls to overridable methods can (and, if your package is popular and/or unlucky enough, will) break your clients.

Trying to write unit tests to verify a subclassing interface is an exercise in frustration; but unless you have adequate coverage, you can't really expect package maintainers not to accidentally break the subclassing contract in any future release.

Subclassing is an important tool in Swift's toolbox, but it takes considerable effort to prepare a class for inheritance. It is not OK to just slap on an "open" keyword and call it done; and it is unsafe to let it happen purely by accident.

Karoly
@lorentey

···

On 2016. Jul 9., at 18:04, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:

Thanks for the thoughtful responses, its appreciated.

2016/07/09 23:30、Matthew Johnson <matthew@anandabits.com> のメール:

Personally, Im not against sealed by default, but I think there are cases where closed source libraries have certain cases where workarounds are necessary, and just sealing by default will prevent those cases.

One could say, "well just use an open source one, or change vendors" but its not that easy in The Real World™ where we get certain SDKs shoved down our throats by the suits… and while that may be a separate issue to the one at hand, its still a problem that won’t resolve itself by simply locking down things…

In my own case, Ive fought with NSBrowser / NSTreeController in the past and the only way to resolve things was to subclass (and no, waiting 1 or 2 years for a fix is not acceptable if you already have a product in the wild).

So I am reticent to support this proposal without an escape hatch for those cases…

Are you concerned about closed-source vendor frameworks beyond Apple’s? Some things to consider:

1. This proposal should not impact any existing libraries - nobody should be shipping closed-source binary libraries written in Swift yet.

2. Apple’s frameworks will probably remain in Objective-C for some time to come. If / when they are replaced with Swift frameworks the default will have little (if any) impact on the public API contract. It is reasonable to expect that Apple will review the public contracts carefully and add any annotations necessary to achieve the desired semantics.

3. In the future, if you depend on any 3rd party closed-source libraries written in Swift you will be able to ship an update to your app that contains an updated / fixed version of the library independent of the user upgrading their OS.

I see, makes sense and I get a better idea where this is going… its how I feel as well...

This leaves the scenario of a case where you depend on a 3rd party, closed-source library written in Swift and where you cannot get (or use) a fix from the vendor for some reason. This is a legitimate concern, but IMO it is not large enough to outweigh all of the advantages of making sealed the default.

What are your thoughts on an ability for a way to force unseal a class that does need to be fixed, even if its temporary?

Something like:

class MyFixedClass : @forceUnseal(SomeSealedClassThatNeedsFixing) { //Emits a scary compiler warning
}

Does that even seem feasible/possible, much less reasonable…?
Though it would have to be a perhaps separate discussion, this comes to my mind as becoming necessary down the road, but maybe I’m wrong...

There is no doubt that adopting sealed by default will place some pressure on the Swift ecosystem. As others have noted, this pressure already exists in the form of value types, protocol-oriented designs, etc - the current proposal is a relatively modest increase in that pressure. I believe the pressure will have a very positive impact over time (the eventual outcome remains to be seen of course).

This is also, to me, a thing I am concerned about… its kind of an unknown I suppose...

Swift library vendors will need to choose between opening their source, providing responsive support and bug fixes, explicitly providing the escape hatch you mention (by designing with open types) or getting a bad reputation among users.

Yes…. Well, anything that gets third parties to open up their closed frameworks is a big win-win IMO… some of them are not very good (to put it mildly) and could use more scrutiny.

I have seen some comments about nontrivial complexity in Apple’s frameworks caused by apps subclassing where they should not have (i.e. classes that would be sealed if it were possible in Objective-C). This is extremely unfortunate and it impacts everyone on Apple’s platforms.

I wish I had links handy for you, but I don’t recall exactly where or when this was mentioned and don’t have time to dig them up right now.

I see, thats reasonable… if those links are available somewhere I would definitely like to see them, it would be a good education for me…

···

On Jul 9, 2016, at 8:39 AM, Andre <pyunpyun@me.com <mailto:pyunpyun@me.com>> wrote:

---

A little more for me to think about, but maybe I can cast a vote in a little bit…

Again, thanks for the thoughtful response!

Andre

Andre

2016/07/09 22:11、Shawn Erickson <shawnce@gmail.com <mailto:shawnce@gmail.com>> のメール:

What I don't get in the arguments against this capability is the fact that many constructs in Swift can't be subclassed. Are we going to prevent library developers from presenting those in the public API? Your ability to subclass things when not supported by the library developer is already going to be greatly reduced. Additionally you are going to miss potentially helpful optimization in side the model if the library developer can't prevent extras subclassing.

It seems perfectly reasonable to allow a lot of freedoms for a library developer when designing their code on their side of the library API and not force them to expose unwanted API just because of internal design desires.

(I have myself have already struggled with having to leak what I consider internal details outside of modules we have developed internally, likely need to get around to outlining the additional issues I see)

In the end if the library isn't good and you don't like the API find one that works the way you need (or make one). I expect a fairly rich environment of libraries that will sort itself out over time.

-Shawn
On Sat, Jul 9, 2016 at 8:43 AM Andre via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
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 <mailto: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 <mailto: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 <mailto: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 <mailto:swift-evolution@swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution

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

P.S. There’s also an argument to be made for public-but-not-conformable protocols, i.e. protocols that can be used in generics and as values outside of a module, but cannot be conformed to. This is important for many of the same reasons as it is for classes, and we’ve gotten a few requests for it. (While you can get a similar effect using an enum, that’s a little less natural for code reuse via protocol extensions.)

Would public-but-not-conformable protocols by default be the next step, then, in Swift's evolution?

I personally think it’s a reasonable place to go next, which is why I brought it up. However, I don’t think it’s critical enough to get into Swift 3 when we’re already so busy, and when there are multiple non-source-breaking ways to get a similar effect later: adding a “sealed” annotation (so, giving up on “by default” for protocols) and allowing requirements to have more narrow access than the protocol (thus making it impossible to conform).

FWIW, if we give up on "by default" for classes, "sealed" could also be a post-Swift 3 matter here as well. IMO, if the core team finds the reasoning here persuasive enough to have sealed-by-default for classes, I'd hope for the same treatment for protocols on that time frame, because as you say much of the rationale behind the change is analogous for both protocols and classes.

On the topic of protocols, there are really two avenues for “sealing”’ them. One is conformances and the other is refinements. There are more nuances to consider in a design for sealing protocols.

If we’re going to continue discussing sealing protocols we should probably start a new thread. However, I think we should wait unless someone from the core team decides it is worth discussing during the Swift 3 timeframe.

···

On Jul 11, 2016, at 1:49 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:
On Mon, Jul 11, 2016 at 11:10 AM, Jordan Rose <jordan_rose@apple.com <mailto:jordan_rose@apple.com>> wrote:

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

Yes. My point was that we already have something equivalent to what’s being proposed, but it’s ad hoc, and interacts poorly with some other features of the language.

Jordan

···

On Jul 11, 2016, at 00:50, Tino Heth via swift-evolution <swift-evolution@swift.org> wrote:

In the implementation of the subclass, there has to be a call to one of the superclass's initializers. If all of the superclass’s initializers are non-public, then there’s no way to write your own initializer. (This is actually true in Swift today.)

I want to point out that this strange behavior can actually be useful:
As of now, you cannot create a public subclass with internal ancestors — it's all or nothing.
When you keep the initializer of the base class internal, you practically seal this class, but it's still possible for framework clients to access the public subclasses supplied for them.

Thanks for the detailed answer — I didn't expect it.

I'll re-order the original message, since you had a genuine question (to bad for me if it was just a rhetorical one :) whose answer might be more interesting than the pointless remarks afterwards ;-)

If you were writing a library, what would make you decide between “experimental” and not?

I guess I would mark everything immature/experimental/whatever on release (as long as it's not to hard to do so…), and then decide step by step wether a method should be public, overridable, private — or removed completely ;-)
Of course, there wouldn't be an universal scale, but most likely each developer/team would keep a reliable standard (some developers are very careful, some are bolder…)
If we are honest, a "sealed" that is only applied because it is the default is actually "experimental" — and in the age of open source, I don't think this should be equivalent to "you can't use this" (some conservative developers consider Swift itself to be immature ;-)
The whole concept is just a spontaneous idea, and maybe I'd come to the conclusion I actually don't like it; but as we can mark stuff as deprecated to notify users that they should stop using a certain method, it might as well be useful to annotate something as unstable to prevent certain developers start using a method (yet).

No, it was a genuine question. I don’t think I agree with your answer, but I’m glad to hear it.

Now for the remarks — they are pointless indeed, because I'm not expecting to change the mind of anyone with a well-grounded opinion

The binary compatibility concerns are less important, but the ability of a library author to reason about behavior is still critical. Here’s a scenario I really don’t want to see happen:

1. Client X adds a dependency on library A, via the package manager. They override a public method in library A to get the behavior they want.
2. Library A ships an update which fixes many bugs and security issues, and happens to eliminate the internal calls to the public method A was using. That is, overriding Athat method no longer has any effect within library A; only clients see the difference.
3. The developer for client X goes to their manager and asks for time to fix the issue. The manager tells them not to update right now, but maybe after this next release.
4. Client X never gets a new version of Library A ever again.

Imho this is remarkable in two aspects:
It is the first real example I'm aware of where I see a true problem, and it "overthrows" (there might be a less dramatic word I'm not aware of) the position that "sealed" primarily solves a problem for library-authors.

I agree that this problem is much less likely with sealed as default, but there's another one in this scenario:
Client X depends on the later-removed feature in Library A — but as this feature isn't accessible for him, he won't ever start using Library A at all…
None the less, I have to admit that I actually prefer the problem in the sealed-scenario, as it doesn't directly effect developer T, but rather pointy-haired boss Y, who just lost a potential customer ;-)

I can't resist to add another culinary comparison to Jonathan Hull's excellent knife-analogy:
As the owner of a restaurant, would you fill your menu with food that's easy to cook to please your chef, or would you rather include food that tastes fantastic to please your customers?

I guess another way of saying this is that library authors avoid these miscommunications by "under-promising”, and if that “under-promising” is something that’s actually in the language instead of maybe/maybe-not being documented, then both sides are much more likely to be on the same page.

Damn, maybe I should have put this in front… why make false promises at all, when you just can tell the truth?

Publishing a library is a promise of something. It ought to only be promises the library author wants to make. If “the truth” is “the implementation in the current version of the library”, that’s definitely not what a library author should promise. That’s true for plenty of things, not just whether or not overriding is expected.

(A client might prefer that the current implementation is what’s promised, but in practice that’s almost never what either side actually wants.)

Jordan

···

On Jul 12, 2016, at 13:44, Tino Heth <2th@gmx.de> wrote:

Publishing a library is a promise of something. It ought to only be promises the library author wants to make. If “the truth” is “the implementation in the current version of the library”, that’s definitely not what a library author should promise. That’s true for plenty of things, not just whether or not overriding is expected.

Correct, library users shouldn't have to puzzle over the authors intention, but I wasn't referring to source when I wrote about truth.
A good library should strive for flexibility, and don't impose restrictions that aren't necessary — "lack of extendability" imho is no promise an author should want to make.
So, what if he wants to promise extendability, but just isn't sure he will be able to stand by this promise? Instead of forcing him into lies, we could as well accept the reality of "I'm not sure", which imho would be the most reasonably default, as it doesn't pretend an explicit choice when there is only uncertainty.

Jonathan Hull outlined an alternative to 0117 (http://article.gmane.org/gmane.comp.lang.swift.evolution/23761\) which takes that into account — and imho has additional benefits:
- More power (for example, UIView.drawRect and other methods that shouldn't be called by clients could be modeled)
- Less confusion ("What's the point of subclassable and overridable? It has no effect on the ability to subclass and override in my app at all!")

Tino

I am all for these things, and would be in favor of a proposal that does this cleanly(*)… the proposal text I reviewed does not.

* e.g. the final/sealed/open keywords you suggest, with sealed being the new default, makes a huge amount of sense to me and feels clean, since it keeps access and finality separate, and as you say, explicitly make decisions in a manner otherwise consistent with the language.

Scott

···

On Jul 6, 2016, at 4:34 PM, Matthew Johnson <matthew@anandabits.com> wrote:

Many of us believe “final” is too blunt a tool. There are many cases where final cannot be used but you still don’t want external users subclassing or overriding.

We would like a more precise tool for these circumstances and believe if it is going to exist in Swift it should be the default. Its behavior follows the principle of requiring programmers to explicitly make decisions about what behavior is exposed outside of a module. You may not like that principle, but it is one that has been embraced by the language.

SE-0117, which we are reviewing here, in its introduction introduces the new `subclassable` and `overridable` modifiers in a discussion about `public`, and indicates that they are used instead of that keyword. This to me strongly implies that these are in the same family as the access control modifiers.

SE-0025 removes the error when the access of a member within a type is less restrictive, thus removes the error that would otherwise occur with the above code.

Consider this another strong argument for keeping access and inheritability separate, the following code would be obviously an error/warning since `open` makes no sense within a `final` class:

  public final class Example {

    public open func foo() {}

  }

Clarity is always a goal for Swift. This to me has more of it than replacing `public`.

Scott

···

On Jul 6, 2016, at 4:34 PM, Matthew Johnson <matthew@anandabits.com> wrote:

To give you an example of the confusion, here is code made perfectly legal by SE-0025:

  public final class Example {

    overridable func foo() {}

  }

I have no idea how you think this is related to SE-0025 (scoped access control). I also don’t understand why you think an `overridable` method in a `final` class would be legal under any proposal. That is nonsense and clearly in error.

Many of us believe “final” is too blunt a tool. There are many cases where final cannot be used but you still don’t want external users subclassing or overriding.

We would like a more precise tool for these circumstances and believe if it is going to exist in Swift it should be the default. Its behavior follows the principle of requiring programmers to explicitly make decisions about what behavior is exposed outside of a module. You may not like that principle, but it is one that has been embraced by the language.

I am all for these things, and would be in favor of a proposal that does this cleanly(*)… the proposal text I reviewed does not.

* e.g. the final/sealed/open keywords you suggest, with sealed being the new default, makes a huge amount of sense to me and feels clean, since it keeps access and finality separate, and as you say, explicitly make decisions in a manner otherwise consistent with the language.

Great! I agree with you that the specific details of the proposal can be improved. The core team is free to "accept with revision" and that's what I hope they do in this case.

···

Sent from my iPad

On Jul 6, 2016, at 6:39 PM, Scott James Remnant <scott@netsplit.com> wrote:

On Jul 6, 2016, at 4:34 PM, Matthew Johnson <matthew@anandabits.com> wrote:

Scott

To give you an example of the confusion, here is code made perfectly legal by SE-0025:

  public final class Example {

    overridable func foo() {}

  }

I have no idea how you think this is related to SE-0025 (scoped access control). I also don’t understand why you think an `overridable` method in a `final` class would be legal under any proposal. That is nonsense and clearly in error.

SE-0117, which we are reviewing here, in its introduction introduces the new `subclassable` and `overridable` modifiers in a discussion about `public`, and indicates that they are used instead of that keyword. This to me strongly implies that these are in the same family as the access control modifiers.

SE-0025 removes the error when the access of a member within a type is less restrictive, thus removes the error that would otherwise occur with the above code.

SE-0025 says nothing about final though. I really don't think we would allow overridable in a final class in any case.

I do think it's fair to point out that details like is are not fully specified in the proposal and should be (in order to avoid another round of cleanup similar to what was necessary for SE-0025).

···

Sent from my iPad

On Jul 6, 2016, at 6:47 PM, Scott James Remnant <scott@netsplit.com> wrote:

On Jul 6, 2016, at 4:34 PM, Matthew Johnson <matthew@anandabits.com> wrote:

Consider this another strong argument for keeping access and inheritability separate, the following code would be obviously an error/warning since `open` makes no sense within a `final` class:

  public final class Example {

    public open func foo() {}

  }

Clarity is always a goal for Swift. This to me has more of it than replacing `public`.

Scott

Thanks for the thoughtful responses, its appreciated.

2016/07/09 23:30、Matthew Johnson <matthew@anandabits.com> のメール:

Personally, Im not against sealed by default, but I think there are cases where closed source libraries have certain cases where workarounds are necessary, and just sealing by default will prevent those cases.

One could say, "well just use an open source one, or change vendors" but its not that easy in The Real World™ where we get certain SDKs shoved down our throats by the suits… and while that may be a separate issue to the one at hand, its still a problem that won’t resolve itself by simply locking down things…

In my own case, Ive fought with NSBrowser / NSTreeController in the past and the only way to resolve things was to subclass (and no, waiting 1 or 2 years for a fix is not acceptable if you already have a product in the wild).

So I am reticent to support this proposal without an escape hatch for those cases…

Are you concerned about closed-source vendor frameworks beyond Apple’s? Some things to consider:

1. This proposal should not impact any existing libraries - nobody should be shipping closed-source binary libraries written in Swift yet.

2. Apple’s frameworks will probably remain in Objective-C for some time to come. If / when they are replaced with Swift frameworks the default will have little (if any) impact on the public API contract. It is reasonable to expect that Apple will review the public contracts carefully and add any annotations necessary to achieve the desired semantics.

3. In the future, if you depend on any 3rd party closed-source libraries written in Swift you will be able to ship an update to your app that contains an updated / fixed version of the library independent of the user upgrading their OS.

I see, makes sense and I get a better idea where this is going… its how I feel as well...

This leaves the scenario of a case where you depend on a 3rd party, closed-source library written in Swift and where you cannot get (or use) a fix from the vendor for some reason. This is a legitimate concern, but IMO it is not large enough to outweigh all of the advantages of making sealed the default.

What are your thoughts on an ability for a way to force unseal a class that does need to be fixed, even if its temporary?

Something like:

class MyFixedClass : @forceUnseal(SomeSealedClassThatNeedsFixing) { //Emits a scary compiler warning
}

Does that even seem feasible/possible, much less reasonable…?

I am also of the opinion that we need an "escape hatch" and I think Joe G notion of patch-ability should be part of this review.

Alternatively I think at least having a way to add:

patch extension mySealedClass {
    defer(methodOnClass(label01:,etc:) ){
         /// code I want to run right after method.
}
}

I think something that is able to run right after a method would help at least some until the library author is able to fix the class. There is probably a small cost on attaching defer code to method but you won't need to subclass to fix certain bugs.

···

On Jul 9, 2016, at 7:59 AM, Andre via swift-evolution <swift-evolution@swift.org> wrote:

On Jul 9, 2016, at 8:39 AM, Andre <pyunpyun@me.com> wrote:

Though it would have to be a perhaps separate discussion, this comes to my mind as becoming necessary down the road, but maybe I’m wrong...

There is no doubt that adopting sealed by default will place some pressure on the Swift ecosystem. As others have noted, this pressure already exists in the form of value types, protocol-oriented designs, etc - the current proposal is a relatively modest increase in that pressure. I believe the pressure will have a very positive impact over time (the eventual outcome remains to be seen of course).

This is also, to me, a thing I am concerned about… its kind of an unknown I suppose...

Swift library vendors will need to choose between opening their source, providing responsive support and bug fixes, explicitly providing the escape hatch you mention (by designing with open types) or getting a bad reputation among users.

Yes…. Well, anything that gets third parties to open up their closed frameworks is a big win-win IMO… some of them are not very good (to put it mildly) and could use more scrutiny.

I have seen some comments about nontrivial complexity in Apple’s frameworks caused by apps subclassing where they should not have (i.e. classes that would be sealed if it were possible in Objective-C). This is extremely unfortunate and it impacts everyone on Apple’s platforms.

I wish I had links handy for you, but I don’t recall exactly where or when this was mentioned and don’t have time to dig them up right now.

I see, thats reasonable… if those links are available somewhere I would definitely like to see them, it would be a good education for me…

---

A little more for me to think about, but maybe I can cast a vote in a little bit…

Again, thanks for the thoughtful response!

Andre

Andre

2016/07/09 22:11、Shawn Erickson <shawnce@gmail.com> のメール:

What I don't get in the arguments against this capability is the fact that many constructs in Swift can't be subclassed. Are we going to prevent library developers from presenting those in the public API? Your ability to subclass things when not supported by the library developer is already going to be greatly reduced. Additionally you are going to miss potentially helpful optimization in side the model if the library developer can't prevent extras subclassing.

It seems perfectly reasonable to allow a lot of freedoms for a library developer when designing their code on their side of the library API and not force them to expose unwanted API just because of internal design desires.

(I have myself have already struggled with having to leak what I consider internal details outside of modules we have developed internally, likely need to get around to outlining the additional issues I see)

In the end if the library isn't good and you don't like the API find one that works the way you need (or make one). I expect a fairly rich environment of libraries that will sort itself out over time.

-Shawn

On Sat, Jul 9, 2016 at 8:43 AM Andre via swift-evolution <swift-evolution@swift.org> wrote:
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

_______________________________________________
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

Thanks for the thoughtful responses, its appreciated.

And thank you for the dialogue and keeping an open mind on this.

2016/07/09 23:30、Matthew Johnson <matthew@anandabits.com> のメール:

Personally, Im not against sealed by default, but I think there are cases where closed source libraries have certain cases where workarounds are necessary, and just sealing by default will prevent those cases.

One could say, "well just use an open source one, or change vendors" but its not that easy in The Real World™ where we get certain SDKs shoved down our throats by the suits… and while that may be a separate issue to the one at hand, its still a problem that won’t resolve itself by simply locking down things…

In my own case, Ive fought with NSBrowser / NSTreeController in the past and the only way to resolve things was to subclass (and no, waiting 1 or 2 years for a fix is not acceptable if you already have a product in the wild).

So I am reticent to support this proposal without an escape hatch for those cases…

Are you concerned about closed-source vendor frameworks beyond Apple’s? Some things to consider:

1. This proposal should not impact any existing libraries - nobody should be shipping closed-source binary libraries written in Swift yet.

2. Apple’s frameworks will probably remain in Objective-C for some time to come. If / when they are replaced with Swift frameworks the default will have little (if any) impact on the public API contract. It is reasonable to expect that Apple will review the public contracts carefully and add any annotations necessary to achieve the desired semantics.

3. In the future, if you depend on any 3rd party closed-source libraries written in Swift you will be able to ship an update to your app that contains an updated / fixed version of the library independent of the user upgrading their OS.

I see, makes sense and I get a better idea where this is going… its how I feel as well...

This leaves the scenario of a case where you depend on a 3rd party, closed-source library written in Swift and where you cannot get (or use) a fix from the vendor for some reason. This is a legitimate concern, but IMO it is not large enough to outweigh all of the advantages of making sealed the default.

What are your thoughts on an ability for a way to force unseal a class that does need to be fixed, even if its temporary?

Something like:

class MyFixedClass : @forceUnseal(SomeSealedClassThatNeedsFixing) { //Emits a scary compiler warning
}

Does that even seem feasible/possible, much less reasonable…?
Though it would have to be a perhaps separate discussion, this comes to my mind as becoming necessary down the road, but maybe I’m wrong...

I'm not opposed to something like this in principle, but I'm not sure how it would work in practice. There was some discussion of something along these lines on the list at one point (I think Joe Groff had some ideas). However, I don't think this is possible if the optimizer takes advantage of the sealed status when the library is compiled. I'll leave it to the compiler experts to comment further on feasibility.

There is no doubt that adopting sealed by default will place some pressure on the Swift ecosystem. As others have noted, this pressure already exists in the form of value types, protocol-oriented designs, etc - the current proposal is a relatively modest increase in that pressure. I believe the pressure will have a very positive impact over time (the eventual outcome remains to be seen of course).

This is also, to me, a thing I am concerned about… its kind of an unknown I suppose...

I agree that it is an unknown. But it's not unprecedented in languages. I think someone mentions Apple's object-based C level APIs as an obvious example where the inability to subclass hasn't been problematic in practice.

Swift library vendors will need to choose between opening their source, providing responsive support and bug fixes, explicitly providing the escape hatch you mention (by designing with open types) or getting a bad reputation among users.

Yes…. Well, anything that gets third parties to open up their closed frameworks is a big win-win IMO… some of them are not very good (to put it mildly) and could use more scrutiny.

Sure, I agree with that. It's worth noting that the choice a library vendor makes about where they want to be on this spectrum provides information that could be useful when evaluating a dependency.

Of course it could be hard to tell the difference between option 2 (responsive support and fixes) vs option 4 (bad reputation) when a library is relatively young - and sometimes a vendor might have better intentions than they do follow-through. But depending on a new library from a vendor with an unknown reputation is always going to be a relatively risky choice to begin with.

I have seen some comments about nontrivial complexity in Apple’s frameworks caused by apps subclassing where they should not have (i.e. classes that would be sealed if it were possible in Objective-C). This is extremely unfortunate and it impacts everyone on Apple’s platforms.

I wish I had links handy for you, but I don’t recall exactly where or when this was mentioned and don’t have time to dig them up right now.

I see, thats reasonable… if those links are available somewhere I would definitely like to see them, it would be a good education for me…

IIRC like Jordan Rose may have made some comments along these lines either on list or on Twitter if you want to search, but that is a fuzzy memory and could easily be wrong. :)

---

A little more for me to think about, but maybe I can cast a vote in a little bit…

Glad it helps!

Again, thanks for the thoughtful response!

You're very welcome! This is will be an important and consequential decision regardless of outcome.

···

Sent from my iPad

On Jul 9, 2016, at 9:59 AM, Andre <pyunpyun@me.com> wrote:

On Jul 9, 2016, at 8:39 AM, Andre <pyunpyun@me.com> wrote:

Andre

Andre

2016/07/09 22:11、Shawn Erickson <shawnce@gmail.com> のメール:

What I don't get in the arguments against this capability is the fact that many constructs in Swift can't be subclassed. Are we going to prevent library developers from presenting those in the public API? Your ability to subclass things when not supported by the library developer is already going to be greatly reduced. Additionally you are going to miss potentially helpful optimization in side the model if the library developer can't prevent extras subclassing.

It seems perfectly reasonable to allow a lot of freedoms for a library developer when designing their code on their side of the library API and not force them to expose unwanted API just because of internal design desires.

(I have myself have already struggled with having to leak what I consider internal details outside of modules we have developed internally, likely need to get around to outlining the additional issues I see)

In the end if the library isn't good and you don't like the API find one that works the way you need (or make one). I expect a fairly rich environment of libraries that will sort itself out over time.

-Shawn

On Sat, Jul 9, 2016 at 8:43 AM Andre via swift-evolution <swift-evolution@swift.org> wrote:
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

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

Why have they not "fixed" this issue with Java 6/7/8 if it is bad to have the current setup by default? Why C++ x09/x11/x14 is also not making everything sealed/unsubclassable by default?

I'd wager a guess that the strong desire not to break source compatibility with existing code explains why Java and C++ are stuck forever with suboptimal defaults. Some members of this list have a bit of background in C++ language design (understatement of the day!); perhaps they know more.

Is it possible that having library authors use something like a sealed keyword or similar is good enough for the default case?

Swift is to be safe by default. I believe open subclassability is a power tool that's unsafe without adequate training and thick protective gear; therefore, it is useful to require posting yellow/black hazard signs when it is in use. Safety first.

"Opting for safety sometimes means Swift will feel strict, but we believe that clarity saves time in the long run."

Karoly
@lorentey

···

On 2016. Jul 9., at 22:55, Goffredo Marocchi <panajev@gmail.com> wrote:

Also "subclassable class" sounds a bit redundant. In other words, I think subclassable implies it is a class.

That's a good point:
There is no inherent reason that you can't inherit from a struct, and that might be possible in a future version of swift.
"subclassable struct MyValue" doesn't read that bad, but depending on how much emphasis is given to the difference of classes and structs, this could be irritating.

But imho the naming is bad anyways:
Both keywords are completely irrelevant for "regular" developers, yet they are directly linked to fundamental concepts of the language.
Removing "overridable" from a method has not the expected effect (you still can override it), and the same is true for subclassable.
Something abstract (like "virtual") would be a little less confusing.