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

+1 from me.

I share similar concerns about 'easily' allowing subclassing within the
module and testability but I am completely for this idea.

···

On Wed, Jul 6, 2016 at 8:33 AM, 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

-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

+1 to this. To me, @testable means “import as if it were internal to this module.”

P

···

On Jul 5, 2016, at 8: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.

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.

L

···

On 6 July 2016 at 16:47, Scott James Remnant via swift-evolution <swift-evolution@swift.org> wrote:

-1

This proposal makes Swift a more confusing language.

Swift already has a mechanism for creating public subclassable classes and
non-subclassable classes:

  public class SubclassableParentClass { }

  public final class NonSubclassableParentClass { }

This mechanism also applies to methods, properties, and subscripts:

  public func bar() {}

  public final func foo() {}

The proposal makes no effort to remove this existing syntax.

The very fact that this would be legitimate syntax as a result is a bad omen
to me:

  subclassable final class ConfusedParentClass {

    overridable final func quuz() {}

  }

The proposal doesn’t even address what that would do, the obvious answer is
“compiler error,” but a better answer would be a language design that didn’t
allow for this kind of ambiguity.

Conflating access control and finality is confusing. The proposal actually
even goes as far to argue that—“conflates” is a word I took from the
proposal—but it’s solution *is* a conflation in of its right, because the
only way to explain the results is in terms of both:

classes, methods, properties, and subscripts with access control of
`internal`, `file private`, and `private` are overridable by code that can
access them, to prevent this add the `final` keyword.
classes with access control of `public` are not overridable by code that can
access them, to allow this replace the `public` keyword with the
`subclassable` keyword.
methods, properties, and subscripts with access control of `public` are not
overridable by code that can access them, to allow this replace the `public`
keyword with the `overridable` keyword.

Not only is this complicated, and confusing, it isn’t even consistent: to
deny overriding or subclassing you add the same keyword; but to allow
overriding or subclassing you replace one keyword with two different ones,
depending on which you’re doing.

I agree that the alternative of flipping the default, and replacing `final`
with `nonfinal` is also undesirable. One of the nicer features of the Swift
language design is that the language is easiest for app developers working
within a single module, where it can be assumed that “everyone is an adult.”
Breaking this to support the less common case of Public API Designers would
be a step backwards; their case is important, but it shouldn’t come at a
penalty.

Scott

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

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

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.

···

Sent from my iPhone

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

I completely agree with rparada and give a strong, strong, strong -1 to this proposal. To make classes non-subclassable by default is only going to lead to unanticipated pain and frustration. Also agree with other comments that subclassable and overridable conflate access control with class behavior. If we want to make it possible to define a class as non-subclassable to external users, I’d agree to something more consistent with existing swift access control like public(final) as has been proposed by other commenters. However, I agree that making classes final by default is a bad idea that will create a larger problem that it solves.

Also, just a more general complaint, I sometimes feel that the evolution list is being dominated by safety enthusiasts at the expense of usability advocates. Safety is a premier feature of Swift, but so is usability. We should be trying to find solutions that advance both objectives, as well as performance and power.

···

On Jul 5, 2016, at 7:11 PM, Chris Lattner<clattner@apple.com(mailto:clattner@apple.com)>wrote:

> 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
>
> * What is your evaluation of the proposal?
-1

Perhaps because this is so different from what I have seen in other languages and used for so many years. I have not worked with a language that uses non-subclassable/ non-overridable as the default.

I think that by default classes should be subclassable, not the other way around. I am afraid that developers will not take the time to specify which methods are overridable resulting in libraries that are difficult to patch, extend.

In my 26+ years of object-oriented design and programming (other languages, Objective-C since 1990 and Java since 2001) I have worked with object oriented libraries and subclassed methods that the authors probably never anticipated. I have been able to fix problems, enhance classes by creating subclasses with fixes and enhanced behavior.

In java for example I have seen that sometimes I would have been able to fix bugs or enhance the existing classes had the author not chosen a method to be protected or private. Sometimes they had a good reason but sometimes they didn't.Is have been able to survive using an awesome library that was discontinued and end-of-lifed thanks to subclassing that has allowed me to fix problems and enhance over the years as the Java language kept evolving.

In general I like to design classes with methods that have a very well defined purpose / logic. Such methods are potentially overridable. I find that making a method private or final can be selfish / restrictive at times and I choose it carefully for implementation details that are better served by going through the public methods.

I think that making a class not subclassable by default is restrictive / limiting / selfish.

Sometimes the extension points are clear.
I also think that every other method with a well defined purpose / logic is also potentially an extension point.

In my experience we should allow the developer to override by default.That is how I design my classes and every method / property.

I use private for the stuff that is obvious that should not be exposed.

In the motivation sectionperformanceis also mentioned as driving this proposal. However I don't see any study that supports that. I would like to see that. This should not be taken lightly.

Let's imagine that performance is important for a library that is heavily used and that the classes are not the type that you usually override. Wouldn't we be better servedby being able to seal the class, i.e. "public sealed class Foo"and then for the methods / properties that are clear extension points should be flaggedoverridable.I would prefer something like that. And I think it would be more intuitive.

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

> * Does this proposal fit well with the feel and direction of Swift?
I think it is counter-intuitive.I don't think that reading "public class Foo" would make anyone think that Foo is non-subclassable.

On the other hand, reading "public class sealed Foo" would suggest to the reader that the class can be overridden but only the methods that are flagged asoverridable.

If we wanted to prohibit overriding then we could use "public final class Foo" without any extension points. Then nobody would be able to subclass and it would be an error to try to flag a method / property as overridable.

> * If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
I don't recall having seen this behavior in the languages that I have worked with.

> * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
I read the whole proposal and have been thinking about the implications for a few hours.

> 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(mailto:swift-evolution-announce@swift.org)
> https://lists.swift.org/mailman/listinfo/swift-evolution-announce

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.

Tino

In the motivation section performance is also mentioned as driving this proposal. However I don't see any study that supports that. I would like to see that. This should not be taken lightly.

There kind of was a discussion on this.

John McCall (http://article.gmane.org/gmane.comp.lang.swift.evolution/22111\)

Finally, the specific form of devirtualization in question here, where a method is proven to never be overridden (again, very common for accessors!), can have a significant impact separate from any calls because the method essentially no longer needs to be virtual. That is, it can be removed from the virtual method tables completely, and we may be able to completely avoid emitting it. That shrinks the size of global memory (and the binary), decrease the amount of work that has to be done at load-time, and improves locality within the virtual table.

I remember that he's mentioned some benchmark final vs. non-final where the difference was in some cases staggering. In general, when you enable whole-module optimization, the compiler can treat all classes within the module as final and optimize mainly accessing properties since they are then known to be final...

···

On Jul 7, 2016, at 1:10 AM, Ricardo Parada via swift-evolution <swift-evolution@swift.org> wrote:

Let's imagine that performance is important for a library that is heavily used and that the classes are not the type that you usually override. Wouldn't we be better served by being able to seal the class, i.e. "public sealed class Foo" and then for the methods / properties that are clear extension points should be flagged overridable. I would prefer something like that. And I think it would be more intuitive.

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

No.

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

I think it is counter-intuitive. I don't think that reading "public class Foo" would make anyone think that Foo is non-subclassable.

On the other hand, reading "public class sealed Foo" would suggest to the reader that the class can be overridden but only the methods that are flagged as overridable.

If we wanted to prohibit overriding then we could use "public final class Foo" without any extension points. Then nobody would be able to subclass and it would be an error to try to flag a method / property as overridable.

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

I don't recall having seen this behavior in the languages that I have worked with.

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

I read the whole proposal and have been thinking about the implications for a few hours.

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 <mailto: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

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?

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.

-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 06-Jul-2016, at 6:03 PM, James Campbell via swift-evolution < swift-evolution@swift.org> wrote:

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

Regards
(From mobile)

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

John has done a tremendous job supporting this proposal; the position he’s articulated very closely matches mine. Thank you to both John and Javier.

I wanted to share a concrete use case that Daniel Dunbar relayed to me. He was working on a closed class hierarchy like the ones discussed here, where all of the subclasses are within a single module, but they are all public. The class also has a required initializer for dynamic construction, so that they could write something like this:

internal struct ModelContext { /*…*/ }

public class ModelBase {
  internal required init(context: ModelContext) { /*…*/ }
  // …
}
public class SimpleModel: ModelBase {
  internal required init(context: ModelContext) { /*…*/ }
}
public class MoreComplicatedModel: ModelBase { /*…*/ }

// (within some other type)
public func instantiateModelObject<Model: ModelBase>(_ type: Model) -> Model {
  return type.init(context: self.context)
}

That is, a public entry point calls a required initializer with an internal argument type. This is the only way to instantiate Model objects, and the internal context type doesn’t leak out into the public API.

Then could it be that in the end it is the entire scaffolding that is poorly structured and in need of fixing, rather than altering the language to make the scaffolding work?

···

On Jul 9, 2016, at 6:39 AM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

Of course, Swift doesn’t allow this. If someone outside of the module subclasses ModelBase, there’s no way for them to provide the dynamically-dispatched 'init(context:)’, because they don’t have access to the internal ModelContext. The author of the library has to make the required initializers public, and either set the ModelContext separately or make it public as well. Even though no one outside the module should be using these APIs.

If ModelBase were public-but-not-subclassable, however, the code is perfectly fine. The initializer and the helper type don’t need to be public, and clients of the library see only what they need.

This is just one use case. I don’t want to say it’s a general model for everyone’s code. However, it does point to a desire for public-and-not-subclassable classes; any other solution would either require the library author making more things public, or the compiler making it possible to accidentally call an unimplemented initializer.

I’ll send a separate message with my thoughts as the primary author of the Library Evolution model, to keep those discussions distinct. That one will have a bit more ideology in it. :-)

Jordan

P.S. “Why not use protocols?” When a protocol has an initializer requirement, it still forces all subclasses of a conforming class to provide an implementation, i.e. the conforming class’s initializer still needs to be declared ‘required’. That means it’s subject to the same restriction: a required initializer must have as much access as the containing class.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Of course, Swift doesn’t allow this. If someone outside of the module subclasses ModelBase, there’s no way for them to provide the dynamically-dispatched 'init(context:)’, because they don’t have access to the internal ModelContext.

Shouldn't Swift allow this? Wouldn't it be better if we found a different way to handle this than a brute force "you shall only subclass if I think you should"? Is that really an impossible cause that is worth us going completely the opposite direction of most programming languages?

Can you tell me why the onus should not be on you, on library authors, to use final or an equivalent keyword to indicate no subclassing is allowed and thus make this intentional?

I am really not sold on why classes should not be subclassable by default. Not all classes suffer of the problem you mention and for those cases you should be able to express your intention explicitly. I am quite against this being a compiler default.

I think that security by ignorance, which is what automagically enforced rules tend to produce over time, does have some side effects.

···

Sent from my iPhone

On 9 Jul 2016, at 05:39, Jordan Rose 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?

···

Sent from my iPhone

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

Can you remind us why does Swift need required initializers to have the same access as the containing class?

Having only package-internal constructors in the public base class is the usual pattern for exporting a sealed class hierarchy in some other languages, like Java.

···

On 2016-07-09 04:39:01 +0000, Jordan Rose via swift-evolution said:

I wanted to share a concrete use case that Daniel Dunbar relayed to me. He was working on a closed class hierarchy like the ones discussed here, where all of the subclasses are within a single module, but they are all public. The class also has a required initializer for dynamic construction, so that they could write something like this:

internal struct ModelContext { /*…*/ }

public class ModelBase {
internal required init(context: ModelContext) { /*…*/ }
// …
}
public class SimpleModel: ModelBase {
internal required init(context: ModelContext) { /*…*/ }
}
public class MoreComplicatedModel: ModelBase { /*…*/ }

// (within some other type)
public func instantiateModelObject<Model: ModelBase>(_ type: Model) -> Model {
return type.init(context: self.context)
}

That is, a public entry point calls a required initializer with an internal argument type. This is the only way to instantiate Model objects, and the internal context type doesn’t leak out into the public API.

Of course, Swift doesn’t allow this. If someone outside of the module subclasses ModelBase, there’s no way for them to provide the dynamically-dispatched 'init(context:)’, because they don’t have access to the internal ModelContext. The author of the library has to make the required initializers public, and either set the ModelContext separately or make it public as well. Even though no one outside the module should be using these APIs.

--
Károly
@lorentey

Sent from my iPad

Huge +1.

Question about inheritance though:

class A {} // Not publicly subclassable
subclassable class B: A {} // Publicly subclassable
class C: B {} // Not publicly subclassable? Or is the subclassability inherited?

This is a great question. There are really two questions:

Can B be marked "subclassable" even though its superclass isn't? Allowing this allows creation of new classes with A as an ancestor. Since this is explicitly opt-in all within the same module I'm inclined to say we should allow it.

Is subclassability inherited by in-module subclasses? This seems to me opposed to the spirit of closed by default. I think it is better to require annotation on *every* class an method that is open to extension outside the module, regardless of what choice a superclass makes,

This gives module authors the most control over *exactly* which classes can be used as superclasses outside the module (A and C don't need to be subclassable just because B needs to be.

I totally agree with both points.

-Thorsten

···

Am 06.07.2016 um 13:39 schrieb Matthew Johnson via swift-evolution <swift-evolution@swift.org>:

On Jul 6, 2016, at 12:24 AM, Charlie Monroe via swift-evolution <swift-evolution@swift.org> wrote:

-Matthew

I'm not a big fan of the subclassable keyword either since it's quite long, not to mention it contains "class" which is the next keyword, making it visually repetitive.

I'd prefer open on both class and func to introduce only one keyword instead of two and possibly make it as a modifier of public to keep it in line with private(set)...

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

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

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

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

(This is my second response to this proposal. The previous message shared
a use case where public-but-non-subclassable made things work out much
better with required initializers. This one has a bit more ideology in it.)

As many people have said already, this proposal is quite beneficial to
library designers attempting to reason about their code, not just now but
in the future as well. The model laid out in the Library Evolution
document <http://jrose-apple.github.io/swift-library-evolution/&gt; (often
referred to as “resilience”) supports Swift libraries that want to preserve
a stable binary and source interface.

In the Swift 2 model (and what’s currently described in that document), a
public class must be final or non-final at the time it is published. It’s
clearly not safe to *add* ‘final' in a later version of the library,
because a client might already have a subclass; it’s also not safe to
*remove* ‘final’ because existing clients may have been compiled assuming
there are no subclasses.

(Of course, we can remove this optimization, and make ‘final’ a semantic
contract only. I’m deliberately avoiding most discussion of performance,
but in this parenthetical I’ll note that Swift makes it possible to write
code that is *slower* than Objective-C. This is considered acceptable
because the compiler can often optimize it for a particular call site. For
those who want more information about the current implementation of some of
Swift’s features, I suggest watching the “Understanding Swift Performance
<Understanding Swift Performance - WWDC16 - Videos - Apple Developer talk from this
year’s WWDC.)

With this proposal, a public class can be non-publicly-subclassable or
publicly-subclassable. Once a class is publicly-subclassable (“open”), you
can’t go back, of course. But a class that’s not initially open could
*become* open in a future release of the library. All existing clients
would already be equipped to deal with this, because there might be
subclasses *inside* the library. On the other hand, the class can *also* be
marked ‘final’, if the library author later realizes there will never be
any subclasses and that both client authors and the compiler should know
this.

One point that’s not covered in this proposal is whether making a class
‘open’ applies retroactively, i.e. if MagicLib 1.2 is the first version
that makes the Magician class ‘open’, can clients deploy back to MagicLib
1.0 and expect their subclasses to work? My inclination is to say no; if
it’s possible for a non-open method to be overridden in the future, a
library author has to write their library as if it will be overridden now,
and there’s no point in making it non-open in the first place. That would
make ‘open’ a “versioned attribute
<Library Evolution Support in Swift (“Resilience”) — Swift 3.0 documentation
in the terminology of Library Evolution, whatever the syntax ends up being.

---

Okay, so why is this important?

It all comes down to reasoning about your program’s behavior. When you use
a class, you’re relying on the documented behavior of that class. More
concretely, the methods on the class have preconditions
(“performSegue(withIdentifier:sender:) should not be called on a view
controller that didn’t come from a storyboard”) and postconditions (“after
calling loadViewIfNeeded(), the view controller’s view will be loaded”).
When you call a method, you’re responsible for satisfying its preconditions
so it can deliver on the postconditions.

I used UIViewController as an example, but it applies just as much to your
own methods. When you call a method in your own module—maybe written by
you, maybe by a coworker, maybe by an open source contributor—you’re
expecting some particular behavior and output given the inputs and the
current state of the program. That is, you just need to satisfy its
preconditions so it can deliver on the postconditions. If it’s a method in
your module, though, you might not have taken the trouble to formalize the
preconditions and postconditions, since you can just go look at the
implementation. Even if your expectations are violated, you’ll probably
notice, because the conflict of understanding is within your own module.

Public overriding changes all this. While an overridable method may have
particular preconditions and postconditions, it’s possible that the
overrider will get that wrong, which means the library author can no longer
reason about the behavior of their program. If they do a poor job
documenting the preconditions and postconditions, the client and the
library will almost certainly disagree about the expected behavior of a
particular method, and the program won’t work correctly.

"Doesn’t a library author have to figure out the preconditions and
postconditions for a method anyway when making it public?" Well, not to the
same extent. It’s perfectly acceptable for a library author to document
stronger preconditions and weaker postconditions than are strictly
necessary. (Maybe 'performSegue(withIdentifier:sender:)’ has a mode that
can work without storyboards, but UIKit isn’t promising that it will work.)
When a library author lets people override their method, though, they're
promising that the method will never be called with a weaker precondition
than documented, and that nothing within their library will expect a
stronger postcondition than documented.

(By the way, the way to look at overriding a method is the inverse of
calling a method: *you* need to deliver on the postconditions, and you
can assume the *caller* has satisfied the preconditions. If your
understanding of those preconditions and postconditions is wrong, your
program won’t work correctly, just like when you’re calling a method.)

This all goes double when a library author wants to release a new version
of their library with different behavior. In order to make sure existing
callers don’t break, they have to make sure all of the library’s documented
preconditions are no stronger and postconditions are no weaker for public
API. In order to make sure existing subclassers don’t break, they have to
make sure all of the library’s documented preconditions are no *weaker* and
postconditions are no *stronger* for overridable API.

(For a very concrete example of this, say you’re calling a method with the
type '(Int?) -> Int’, and you’re passing nil. The new version of the
library can’t decide to make the parameter non-optional or the return value
optional, because that would break your code. Similarly, if you’re
*overriding* a method with the type ‘(Int) -> Int?’, and *returning* nil,
the new version of the library can’t decide to make the parameter
*optional* or the return value *non-*optional, because *that* would break
your code.)

So, "non-publicly-subclassable" is a way to ease the burden on a library
author. They should be thinking about preconditions and postconditions in
their program *anyway,* but not having to worry about all the things a
client might do for a method that *shouldn’t* be overridden means they
can actually reason about the behavior—and thus the correctness—of their
own program, both now and for future releases.

---

I agree with several people on this thread that
non-publicly-subclassable-by-default is the same idea as
internal-by-default: it means that you have to explicitly decide to support
a capability before clients can start relying on it, and you are very
unlikely to do so by accident. The default is “safe” in that a library
author can change their mind without breaking existing clients.

I agree with John that even today, the entry points that *happen* to be
public in the types that *happen* to be public classes are unlikely to be
good entry points for fixing bugs in someone else's library. Disallowing
overriding these particular entry points when a client already can't
override internal methods, methods on structs, methods that use internal
types, or top-level functions doesn’t really seem like a loss to me.

Library design is important. Controlling the public interface of a library
allows for better reasoning about the behavior of code, better security
(i.e. better protection of user data), and better maintainability. And
whether something can be overridden is part of that interface.

Thanks again to Javier and John for putting this proposal together.
Jordan

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?

···

On Sun, Jul 10, 2016 at 10:38 PM, Jordan Rose via swift-evolution < swift-evolution@swift.org> wrote:

P.P.S. For those who will argue against “better security”, you’re correct:
this *doesn’t* prevent an attack, and I *don’t* have much expertise in
this area. However, I *have* talked to developers distributing binary
frameworks (despite our warnings that it isn’t supported) who have asked us
for various features to keep it from being *easy.*

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

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

(This is my second response to this proposal. The previous message shared a use case where public-but-non-subclassable made things work out much better with required initializers. This one has a bit more ideology in it.)

As many people have said already, this proposal is quite beneficial to library designers attempting to reason about their code, not just now but in the future as well. The model laid out in the Library Evolution document (often referred to as “resilience”) supports Swift libraries that want to preserve a stable binary and source interface.

In the Swift 2 model (and what’s currently described in that document), a public class must be final or non-final at the time it is published. It’s clearly not safe to add ‘final' in a later version of the library, because a client might already have a subclass; it’s also not safe to remove ‘final’ because existing clients may have been compiled assuming there are no subclasses.

(Of course, we can remove this optimization, and make ‘final’ a semantic contract only. I’m deliberately avoiding most discussion of performance, but in this parenthetical I’ll note that Swift makes it possible to write code that is slower than Objective-C. This is considered acceptable because the compiler can often optimize it for a particular call site. For those who want more information about the current implementation of some of Swift’s features, I suggest watching the “Understanding Swift Performance” talk from this year’s WWDC.)

With this proposal, a public class can be non-publicly-subclassable or publicly-subclassable. Once a class is publicly-subclassable (“open”), you can’t go back, of course. But a class that’s not initially open could become open in a future release of the library. All existing clients would already be equipped to deal with this, because there might be subclasses inside the library. On the other hand, the class can also be marked ‘final’, if the library author later realizes there will never be any subclasses and that both client authors and the compiler should know this.

One point that’s not covered in this proposal is whether making a class ‘open’ applies retroactively, i.e. if MagicLib 1.2 is the first version that makes the Magician class ‘open’, can clients deploy back to MagicLib 1.0 and expect their subclasses to work? My inclination is to say no; if it’s possible for a non-open method to be overridden in the future, a library author has to write their library as if it will be overridden now, and there’s no point in making it non-open in the first place. That would make ‘open’ a “versioned attribute” in the terminology of Library Evolution, whatever the syntax ends up being.

---

Okay, so why is this important?

It all comes down to reasoning about your program’s behavior. When you use a class, you’re relying on the documented behavior of that class. More concretely, the methods on the class have preconditions (“performSegue(withIdentifier:sender:) should not be called on a view controller that didn’t come from a storyboard”) and postconditions (“after calling loadViewIfNeeded(), the view controller’s view will be loaded”). When you call a method, you’re responsible for satisfying its preconditions so it can deliver on the postconditions.

I used UIViewController as an example, but it applies just as much to your own methods. When you call a method in your own module—maybe written by you, maybe by a coworker, maybe by an open source contributor—you’re expecting some particular behavior and output given the inputs and the current state of the program. That is, you just need to satisfy its preconditions so it can deliver on the postconditions. If it’s a method in your module, though, you might not have taken the trouble to formalize the preconditions and postconditions, since you can just go look at the implementation. Even if your expectations are violated, you’ll probably notice, because the conflict of understanding is within your own module.

Public overriding changes all this. While an overridable method may have particular preconditions and postconditions, it’s possible that the overrider will get that wrong, which means the library author can no longer reason about the behavior of their program. If they do a poor job documenting the preconditions and postconditions, the client and the library will almost certainly disagree about the expected behavior of a particular method, and the program won’t work correctly.

"Doesn’t a library author have to figure out the preconditions and postconditions for a method anyway when making it public?" Well, not to the same extent. It’s perfectly acceptable for a library author to document stronger preconditions and weaker postconditions than are strictly necessary. (Maybe 'performSegue(withIdentifier:sender:)’ has a mode that can work without storyboards, but UIKit isn’t promising that it will work.) When a library author lets people override their method, though, they're promising that the method will never be called with a weaker precondition than documented, and that nothing within their library will expect a stronger postcondition than documented.

(By the way, the way to look at overriding a method is the inverse of calling a method: you need to deliver on the postconditions, and you can assume the caller has satisfied the preconditions. If your understanding of those preconditions and postconditions is wrong, your program won’t work correctly, just like when you’re calling a method.)

This all goes double when a library author wants to release a new version of their library with different behavior. In order to make sure existing callers don’t break, they have to make sure all of the library’s documented preconditions are no stronger and postconditions are no weaker for public API. In order to make sure existing subclassers don’t break, they have to make sure all of the library’s documented preconditions are no weaker and postconditions are no stronger for overridable API.

(For a very concrete example of this, say you’re calling a method with the type '(Int?) -> Int’, and you’re passing nil. The new version of the library can’t decide to make the parameter non-optional or the return value optional, because that would break your code. Similarly, if you’re overriding a method with the type ‘(Int) -> Int?’, and returning nil, the new version of the library can’t decide to make the parameter optional or the return value non-optional, because that would break your code.)

So, "non-publicly-subclassable" is a way to ease the burden on a library author. They should be thinking about preconditions and postconditions in their program anyway, but not having to worry about all the things a client might do for a method that shouldn’t be overridden means they can actually reason about the behavior—and thus the correctness—of their own program, both now and for future releases.

---

I agree with several people on this thread that non-publicly-subclassable-by-default is the same idea as internal-by-default: it means that you have to explicitly decide to support a capability before clients can start relying on it, and you are very unlikely to do so by accident. The default is “safe” in that a library author can change their mind without breaking existing clients.

I agree with John that even today, the entry points that happen to be public in the types that happen to be public classes are unlikely to be good entry points for fixing bugs in someone else's library. Disallowing overriding these particular entry points when a client already can't override internal methods, methods on structs, methods that use internal types, or top-level functions doesn’t really seem like a loss to me.

Library design is important. Controlling the public interface of a library allows for better reasoning about the behavior of code, better security (i.e. better protection of user data), and better maintainability. And whether something can be overridden is part of that interface.

Thanks again to Javier and John for putting this proposal together.
Jordan

Thanks for this really excellent, detailed analysis of the rationale for making sealed the default Jordan!

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.)

FYI - I have been planning to propose exactly this feature for protocols once we get past the Swift 3 additive feature freeze.

···

Sent from my iPad

On Jul 10, 2016, at 10:38 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

P.P.S. For those who will argue against “better security”, you’re correct: this doesn’t prevent an attack, and I don’t have much expertise in this area. However, I have talked to developers distributing binary frameworks (despite our warnings that it isn’t supported) who have asked us for various features to keep it from being easy.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I haven't read the whole Library Evolution document, but one important part is written right at the top:

This model is largely not of interest to libraries that are bundled with their clients (distribution via source, static library, or embedded/sandboxed dynamic library, as used by the Swift Package Manager <https://swift.org/package-manager/&gt;\)

So there are compelling arguments to "seal" the Apple-libraries, and it's reasonable to enforce sealing on them.
But if sealed is the right default for those libraries, it is not automatically the right default for all other libraries out there, because those are developed in a completely different manner.
So, instead making sealed the default for Swift, I believe it is much more sound to just make it the default for the standard frameworks:
This doesn't break compatibility, it's imho more convenient for the majority, and I guess there is enough manpower to manage the annotations for Cocoa and other frameworks (which is tedious labor for single developers, but no issue for a large company).

···

Am 11.07.2016 um 05:38 schrieb Jordan Rose via swift-evolution <swift-evolution@swift.org>:

While an overridable method may have particular preconditions and postconditions, it’s possible that the overrider will get that wrong, which means the library author can no longer reason about the behavior of their program.

Once again a situation where we have to differentiate wether we encourage open source or not:
In OS, users of a library become the allies of its author — they can put stress on his model, they can find its flaws and they can show him how to improve.
The ability to take a piece of code and start playing with it is a fantastic trait, and this is actively discouraged by imposing limits not because they make sense, but only because the original author didn't take the time to reason about the status.

For software that grows "organically", documentation is more useful than simple rules...
I like the concept of version blocks, and it could work in the other direction as well: We could have a "experimental"-modifier that would give the library author a way to offer hints for its clients, but leaves the final decision up to them. This would be much more granular than a plain "final" which not only protects those who want to stay on the safe side, but also repels the bold developers who'd willingly help improving the code in question.

Just a though, but why sealed classes have to be completely unsubclassable ?

Wouldn't it be possible to allow the user to subclass sealed class, but deny overriding of any public member.

I see a use case where a user want to extends an existing model by adding new properties and new methods to an object but can’t use composition because doing that will prevent to pass that object to the framework that expect the base object.

That would let user override existing class to extends them, but should not cause any side effect in the way the class should behave, and so would not affects preconditions and postconditions, and should not prevent optimization in whole module compilation, as the methods of the base class are considered final outside of the module.

Of course, it will introduce some fragility in the library, as adding new methods may conflict with user subclass methods, but no more than what would append if the user write extension to add new methods to the model.

···

Le 11 juil. 2016 à 05:38, Jordan Rose via swift-evolution <swift-evolution@swift.org> a écrit :

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

(This is my second response to this proposal. The previous message shared a use case where public-but-non-subclassable made things work out much better with required initializers. This one has a bit more ideology in it.)

As many people have said already, this proposal is quite beneficial to library designers attempting to reason about their code, not just now but in the future as well. The model laid out in the Library Evolution document <http://jrose-apple.github.io/swift-library-evolution/&gt; (often referred to as “resilience”) supports Swift libraries that want to preserve a stable binary and source interface.

In the Swift 2 model (and what’s currently described in that document), a public class must be final or non-final at the time it is published. It’s clearly not safe to add ‘final' in a later version of the library, because a client might already have a subclass; it’s also not safe to remove ‘final’ because existing clients may have been compiled assuming there are no subclasses.

(Of course, we can remove this optimization, and make ‘final’ a semantic contract only. I’m deliberately avoiding most discussion of performance, but in this parenthetical I’ll note that Swift makes it possible to write code that is slower than Objective-C. This is considered acceptable because the compiler can often optimize it for a particular call site. For those who want more information about the current implementation of some of Swift’s features, I suggest watching the “Understanding Swift Performance <Understanding Swift Performance - WWDC16 - Videos - Apple Developer talk from this year’s WWDC.)

With this proposal, a public class can be non-publicly-subclassable or publicly-subclassable. Once a class is publicly-subclassable (“open”), you can’t go back, of course. But a class that’s not initially open could become open in a future release of the library. All existing clients would already be equipped to deal with this, because there might be subclasses inside the library. On the other hand, the class can also be marked ‘final’, if the library author later realizes there will never be any subclasses and that both client authors and the compiler should know this.

One point that’s not covered in this proposal is whether making a class ‘open’ applies retroactively, i.e. if MagicLib 1.2 is the first version that makes the Magician class ‘open’, can clients deploy back to MagicLib 1.0 and expect their subclasses to work? My inclination is to say no; if it’s possible for a non-open method to be overridden in the future, a library author has to write their library as if it will be overridden now, and there’s no point in making it non-open in the first place. That would make ‘open’ a “versioned attribute <Library Evolution Support in Swift (“Resilience”) — Swift 3.0 documentation in the terminology of Library Evolution, whatever the syntax ends up being.

---

Okay, so why is this important?

It all comes down to reasoning about your program’s behavior. When you use a class, you’re relying on the documented behavior of that class. More concretely, the methods on the class have preconditions (“performSegue(withIdentifier:sender:) should not be called on a view controller that didn’t come from a storyboard”) and postconditions (“after calling loadViewIfNeeded(), the view controller’s view will be loaded”). When you call a method, you’re responsible for satisfying its preconditions so it can deliver on the postconditions.

I used UIViewController as an example, but it applies just as much to your own methods. When you call a method in your own module—maybe written by you, maybe by a coworker, maybe by an open source contributor—you’re expecting some particular behavior and output given the inputs and the current state of the program. That is, you just need to satisfy its preconditions so it can deliver on the postconditions. If it’s a method in your module, though, you might not have taken the trouble to formalize the preconditions and postconditions, since you can just go look at the implementation. Even if your expectations are violated, you’ll probably notice, because the conflict of understanding is within your own module.

Public overriding changes all this. While an overridable method may have particular preconditions and postconditions, it’s possible that the overrider will get that wrong, which means the library author can no longer reason about the behavior of their program. If they do a poor job documenting the preconditions and postconditions, the client and the library will almost certainly disagree about the expected behavior of a particular method, and the program won’t work correctly.

"Doesn’t a library author have to figure out the preconditions and postconditions for a method anyway when making it public?" Well, not to the same extent. It’s perfectly acceptable for a library author to document stronger preconditions and weaker postconditions than are strictly necessary. (Maybe 'performSegue(withIdentifier:sender:)’ has a mode that can work without storyboards, but UIKit isn’t promising that it will work.) When a library author lets people override their method, though, they're promising that the method will never be called with a weaker precondition than documented, and that nothing within their library will expect a stronger postcondition than documented.

(By the way, the way to look at overriding a method is the inverse of calling a method: you need to deliver on the postconditions, and you can assume the caller has satisfied the preconditions. If your understanding of those preconditions and postconditions is wrong, your program won’t work correctly, just like when you’re calling a method.)

This all goes double when a library author wants to release a new version of their library with different behavior. In order to make sure existing callers don’t break, they have to make sure all of the library’s documented preconditions are no stronger and postconditions are no weaker for public API. In order to make sure existing subclassers don’t break, they have to make sure all of the library’s documented preconditions are no weaker and postconditions are no stronger for overridable API.

(For a very concrete example of this, say you’re calling a method with the type '(Int?) -> Int’, and you’re passing nil. The new version of the library can’t decide to make the parameter non-optional or the return value optional, because that would break your code. Similarly, if you’re overriding a method with the type ‘(Int) -> Int?’, and returning nil, the new version of the library can’t decide to make the parameter optional or the return value non-optional, because that would break your code.)

So, "non-publicly-subclassable" is a way to ease the burden on a library author. They should be thinking about preconditions and postconditions in their program anyway, but not having to worry about all the things a client might do for a method that shouldn’t be overridden means they can actually reason about the behavior—and thus the correctness—of their own program, both now and for future releases.

---

I agree with several people on this thread that non-publicly-subclassable-by-default is the same idea as internal-by-default: it means that you have to explicitly decide to support a capability before clients can start relying on it, and you are very unlikely to do so by accident. The default is “safe” in that a library author can change their mind without breaking existing clients.

I agree with John that even today, the entry points that happen to be public in the types that happen to be public classes are unlikely to be good entry points for fixing bugs in someone else's library. Disallowing overriding these particular entry points when a client already can't override internal methods, methods on structs, methods that use internal types, or top-level functions doesn’t really seem like a loss to me.

Library design is important. Controlling the public interface of a library allows for better reasoning about the behavior of code, better security (i.e. better protection of user data), and better maintainability. And whether something can be overridden is part of that interface.

Thanks again to Javier and John for putting this proposal together.
Jordan

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.)

P.P.S. For those who will argue against “better security”, you’re correct: this doesn’t prevent an attack, and I don’t have much expertise in this area. However, I have talked to developers distributing binary frameworks (despite our warnings that it isn’t supported) who have asked us for various features to keep it from being easy.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution