'Public' class visibility specifiers

OK, here comes the girl with the big wooden spoon to stir things up a bit ;-)

When it comes to visibilities on classes, why, oh why do we have public vs open *as well as*
the option of marking stuff as final?

Surely, outside the module boundary :

1. public is the same as final ; i.e. you can see it but you can't derive from/override it

2. open is the same as public without final ; you can see it and derive from/override it

Inside the module boundary, there is essentially no difference between public and open.

In fact, open/public is a conflation of concerns.

Both allow public visibility but, mixed in with that is restriction of inheritance. Surely public is good enough for visibility and final is good enough for inheritance restriction?

////////////////
// Module1 file

// MARK: base classes

open class OpenClass
{
  open func test() { }
}

public class PublicClass
{
  public func test() { }
  
  public final func finalTest() { }
}

public final class FinalPublicClass
{
  public final func test() { }
}

// MARK: derived internal classes

class FrameworkDerivedPublicClass : PublicClass
{
  override func test() { }
  
  override func finalTest() { } // error : instance method overrides a 'final' instance method
}

class FrameworkDerivedFinalPublicClass : FinalPublicClass // error : inheritance from a final class
{
  override func test() { } // error : instance method overrides a 'final' instance method
}
///////////////

///////////////
// Module2 file

class OpenSubclass : OpenClass
{
  override func test() { }
}

class PublicSubclass : PublicClass // error : cannot inherit from non-open class 'PublicClass' outside of its defining module
{
  override func test() { } // error : overriding non-open instance method outside of its defining module
  
  override func finalTest() { } // error : method does not override any method from its superclass
}

class FinalPublicSubclass : FinalPublicClass // error : cannot inherit from non-open class 'FinalPublicClass' outside of its defining module
{
  override func test() { } // error : instance method overrides a 'final' instance method
                                           // error : overriding non-open instance method outside of its defining module
}
////////////////

In fact, the test() method in FinalPublicSubclass gives two errors one of which is the same as when declared in FrameworkDerivedFinalPublicClass.

If final is good enough for inside the module boundary, and the same "overriding final method" error appears in both places, do we really need this added complexity?

Surely, if we take public as meaning no inheritance control anywhere :

public class BaseClass
{
  public func test() { }
  
  public final func finalTest() { }
}

And then, either in or out of the module :

class DerivedClass : BaseClass
{
  override func test() { }
  
  override func finalTest() { } // error : instance method overrides a 'final' instance method
}

Or, if BaseClass were marked as final, then inheritance of the whole class is prohibited.

So, I am proposing a reduction in keywords from open, public and final, to just public and final.

···

--
Joanna Carter
Carter Consulting

OK, here comes the girl with the big wooden spoon to stir things up a bit ;-)

When it comes to visibilities on classes, why, oh why do we have public vs open *as well as*
the option of marking stuff as final?

Surely, outside the module boundary :

1. public is the same as final ; i.e. you can see it but you can't derive from/override it

2. open is the same as public without final ; you can see it and derive from/override it

Inside the module boundary, there is essentially no difference between public and open.

In fact, open/public is a conflation of concerns.

Both allow public visibility but, mixed in with that is restriction of inheritance. Surely public is good enough for visibility and final is good enough for inheritance restriction?

////////////////
// Module1 file

// MARK: base classes

open class OpenClass
{
  open func test() { }
}

public class PublicClass
{
  public func test() { }

  public final func finalTest() { }
}

public final class FinalPublicClass
{
  public final func test() { }
}

// MARK: derived internal classes

class FrameworkDerivedPublicClass : PublicClass
{
  override func test() { }

  override func finalTest() { } // error : instance method overrides a 'final' instance method
}

class FrameworkDerivedFinalPublicClass : FinalPublicClass // error : inheritance from a final class
{
  override func test() { } // error : instance method overrides a 'final' instance method
}
///////////////

///////////////
// Module2 file

class OpenSubclass : OpenClass
{
  override func test() { }
}

class PublicSubclass : PublicClass // error : cannot inherit from non-open class 'PublicClass' outside of its defining module
{
  override func test() { } // error : overriding non-open instance method outside of its defining module

  override func finalTest() { } // error : method does not override any method from its superclass
}

class FinalPublicSubclass : FinalPublicClass // error : cannot inherit from non-open class 'FinalPublicClass' outside of its defining module
{
  override func test() { } // error : instance method overrides a 'final' instance method
                                           // error : overriding non-open instance method outside of its defining module
}
////////////////

In fact, the test() method in FinalPublicSubclass gives two errors one of which is the same as when declared in FrameworkDerivedFinalPublicClass.

If final is good enough for inside the module boundary, and the same "overriding final method" error appears in both places, do we really need this added complexity?

Surely, if we take public as meaning no inheritance control anywhere :

public class BaseClass
{
  public func test() { }

  public final func finalTest() { }
}

And then, either in or out of the module :

class DerivedClass : BaseClass
{
  override func test() { }

  override func finalTest() { } // error : instance method overrides a 'final' instance method
}

Or, if BaseClass were marked as final, then inheritance of the whole class is prohibited.

So, I am proposing a reduction in keywords from open, public and final, to just public and final.

With 'public' we can't have subtypes outside of the module, but can have subtypes inside the module. With 'final' you can't have subtype even inside module.
That was the main idea, that your module knows all the possible subtypes of some type.

···

On 20.02.2017 19:47, Joanna Carter via swift-evolution wrote:

--
Joanna Carter
Carter Consulting

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

OK, here comes the girl with the big wooden spoon to stir things up a bit ;-)

When it comes to visibilities on classes, why, oh why do we have public vs open *as well as*
the option of marking stuff as final?

Surely, outside the module boundary :

1. public is the same as final ; i.e. you can see it but you can't derive from/override it

There is one important difference, but it is rather obscure. ‘final’ allows a class to conform to protocols where ’Self’ appears in invariant position in requirements. For example, say you have the following:

struct G<T> {}

protocol P {
  func foo(_: G<Self>)
}

class C {} // either inside your module, or elsewhere

The following is not allowed, and produces an error:

extension C : P {
  func foo(_: G<C>) {} // ‘Self’ appears in non-parameter, non-result position
}

The reason being that if you have a subclass D of C, the signature of foo() no longer matches the requirement — the caller expects to pass in a G<D>, not a G<C>. Recall that D < C does not imply G<D> < G<C> in Swift.

Note that even if ‘C’ is public and not open, we cannot allow the above conformance, because the module that defined ‘C’ might later on add a new subclass, invalidating the conformance.

If ‘C’ is final, this is OK though — we know there will be no other subclasses, so ‘Self’ and ‘C’ are indeed interchangeable.

Also worth noting that removing ‘final’ from a class is going to be an ABI breaking change (and source compatibility too), whereas changing a ‘public’ class to ‘open’ poses no such difficulty.

I might be in favor of a proposal to just remove ‘final’ altogether, though, leaving us with just open and public. I’m not sure how much the ability for classes to conform to such protocols matters in practice.

Slava

···

On Feb 20, 2017, at 8:47 AM, Joanna Carter via swift-evolution <swift-evolution@swift.org> wrote:

2. open is the same as public without final ; you can see it and derive from/override it

Inside the module boundary, there is essentially no difference between public and open.

In fact, open/public is a conflation of concerns.

Both allow public visibility but, mixed in with that is restriction of inheritance. Surely public is good enough for visibility and final is good enough for inheritance restriction?

////////////////
// Module1 file

// MARK: base classes

open class OpenClass
{
open func test() { }
}

public class PublicClass
{
public func test() { }

public final func finalTest() { }
}

public final class FinalPublicClass
{
public final func test() { }
}

// MARK: derived internal classes

class FrameworkDerivedPublicClass : PublicClass
{
override func test() { }

override func finalTest() { } // error : instance method overrides a 'final' instance method
}

class FrameworkDerivedFinalPublicClass : FinalPublicClass // error : inheritance from a final class
{
override func test() { } // error : instance method overrides a 'final' instance method
}
///////////////

///////////////
// Module2 file

class OpenSubclass : OpenClass
{
override func test() { }
}

class PublicSubclass : PublicClass // error : cannot inherit from non-open class 'PublicClass' outside of its defining module
{
override func test() { } // error : overriding non-open instance method outside of its defining module

override func finalTest() { } // error : method does not override any method from its superclass
}

class FinalPublicSubclass : FinalPublicClass // error : cannot inherit from non-open class 'FinalPublicClass' outside of its defining module
{
override func test() { } // error : instance method overrides a 'final' instance method
                                          // error : overriding non-open instance method outside of its defining module
}
////////////////

In fact, the test() method in FinalPublicSubclass gives two errors one of which is the same as when declared in FrameworkDerivedFinalPublicClass.

If final is good enough for inside the module boundary, and the same "overriding final method" error appears in both places, do we really need this added complexity?

Surely, if we take public as meaning no inheritance control anywhere :

public class BaseClass
{
public func test() { }

public final func finalTest() { }
}

And then, either in or out of the module :

class DerivedClass : BaseClass
{
override func test() { }

override func finalTest() { } // error : instance method overrides a 'final' instance method
}

Or, if BaseClass were marked as final, then inheritance of the whole class is prohibited.

So, I am proposing a reduction in keywords from open, public and final, to just public and final.

--
Joanna Carter
Carter Consulting

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

We had an enormous, weeks-long, *hugely* contentious debate about whether to introduce `open`, and the end result was that SE-0117 was revised several times and finally approved. It describes the rationale concisely, but pretty well: <https://github.com/apple/swift-evolution/blob/master/proposals/0117-non-public-subclassable-by-default.md&gt;

It doesn't *specifically* address why `final` was kept as well, but essentially, as the Motivation section describes, we wanted non-inheritable to be the default for public classes, so developers would have to specifically choose to open their classes to public subclassing. That meant that having `public` make the class subclassable would not fulfill our goals.

Look. It's not forbidden to re-litigate old design decisions, but if you're going to do it, you should at least study the original proposal and be prepared to either attack flaws in the Motivation section or show why the Proposed Design does not address the problem. Preferably, you should base your argument knowledge from later experience--things we did not know when we reviewed the proposal. You're not saying anything in this thread that wasn't said over and over again in a series of sprawling, stressful near-flamewars last summer.

Please don't tear open old wounds unless you at least have a new treatment to try.

···

On Feb 20, 2017, at 8:47 AM, Joanna Carter via swift-evolution <swift-evolution@swift.org> wrote:

When it comes to visibilities on classes, why, oh why do we have public vs open *as well as*
the option of marking stuff as final?

--
Brent Royal-Gordon
Architechies

I’d agree with the proposition of eliminating open.
It does look as an additional layer of complexity for a use case that is imho not so common.

···

On 20 Feb 2017, at 18:07, Vladimir.S via swift-evolution <swift-evolution@swift.org<mailto:swift-evolution@swift.org>> wrote:

On 20.02.2017 19:47, Joanna Carter via swift-evolution wrote:
OK, here comes the girl with the big wooden spoon to stir things up a bit ;-)

When it comes to visibilities on classes, why, oh why do we have public vs open *as well as*
the option of marking stuff as final?

Surely, outside the module boundary :

1. public is the same as final ; i.e. you can see it but you can't derive from/override it

2. open is the same as public without final ; you can see it and derive from/override it

Inside the module boundary, there is essentially no difference between public and open.

In fact, open/public is a conflation of concerns.

Both allow public visibility but, mixed in with that is restriction of inheritance. Surely public is good enough for visibility and final is good enough for inheritance restriction?

////////////////
// Module1 file

// MARK: base classes

open class OpenClass
{
open func test() { }
}

public class PublicClass
{
public func test() { }

public final func finalTest() { }
}

public final class FinalPublicClass
{
public final func test() { }
}

// MARK: derived internal classes

class FrameworkDerivedPublicClass : PublicClass
{
override func test() { }

override func finalTest() { } // error : instance method overrides a 'final' instance method
}

class FrameworkDerivedFinalPublicClass : FinalPublicClass // error : inheritance from a final class
{
override func test() { } // error : instance method overrides a 'final' instance method
}
///////////////

///////////////
// Module2 file

class OpenSubclass : OpenClass
{
override func test() { }
}

class PublicSubclass : PublicClass // error : cannot inherit from non-open class 'PublicClass' outside of its defining module
{
override func test() { } // error : overriding non-open instance method outside of its defining module

override func finalTest() { } // error : method does not override any method from its superclass
}

class FinalPublicSubclass : FinalPublicClass // error : cannot inherit from non-open class 'FinalPublicClass' outside of its defining module
{
override func test() { } // error : instance method overrides a 'final' instance method
                                          // error : overriding non-open instance method outside of its defining module
}
////////////////

In fact, the test() method in FinalPublicSubclass gives two errors one of which is the same as when declared in FrameworkDerivedFinalPublicClass.

If final is good enough for inside the module boundary, and the same "overriding final method" error appears in both places, do we really need this added complexity?

Surely, if we take public as meaning no inheritance control anywhere :

public class BaseClass
{
public func test() { }

public final func finalTest() { }
}

And then, either in or out of the module :

class DerivedClass : BaseClass
{
override func test() { }

override func finalTest() { } // error : instance method overrides a 'final' instance method
}

Or, if BaseClass were marked as final, then inheritance of the whole class is prohibited.

So, I am proposing a reduction in keywords from open, public and final, to just public and final.

With 'public' we can't have subtypes outside of the module, but can have subtypes inside the module. With 'final' you can't have subtype even inside module.
That was the main idea, that your module knows all the possible subtypes of some type.

--
Joanna Carter
Carter Consulting

_______________________________________________
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

Yes I do.

···

On 20 Feb 2017, at 18:53, Joanna Carter <joanna@carterconsulting.org.uk> wrote:

Le 20 févr. 2017 à 18:21, Dimitri Racordon <Dimitri.Racordon@unige.ch> a écrit :

I’d agree with the proposition of eliminating open.
It does look as an additional layer of complexity for a use case that is imho not so common.

Do you think it's worth a formal proposal?

--
Joanna Carter
Carter Consulting

If you want to limit visibility of anything to within the module, what's wrong with internal?

Final isn't about visibility, it's about restriction of inheritance, whether the class is visible outside the module or not

···

Le 20 févr. 2017 à 18:07, Vladimir.S <svabox@gmail.com> a écrit :

With 'public' we can't have subtypes outside of the module, but can have subtypes inside the module. With 'final' you can't have subtype even inside module.
That was the main idea, that your module knows all the possible subtypes of some type.

--
Joanna Carter
Carter Consulting

Sorry I pressed the wrong button, and the mail was sent right away.
I was about to add that I could give it a try, or offer my help.

Do you think it's worth a formal proposal?

···

Le 20 févr. 2017 à 18:21, Dimitri Racordon <Dimitri.Racordon@unige.ch> a écrit :

I’d agree with the proposition of eliminating open.
It does look as an additional layer of complexity for a use case that is imho not so common.

--
Joanna Carter
Carter Consulting

Since I still haven't worked out how to submit a proposal, if you know how to, maybe you should take the lead.

If you want to contact me offline during the preparation, please feel free

···

Le 20 févr. 2017 à 19:18, Dimitri Racordon <Dimitri.Racordon@unige.ch> a écrit :

Sorry I pressed the wrong button, and the mail was sent right away.
I was about to add that I could give it a try, or offer my help.

--
Joanna Carter
Carter Consulting

I am not advocating removing 'final' from the language ; rather of removing 'open', which is "foreign" to anyone coming from any other language.

My suggestion was to revert 'open' back to 'public' for visibility purposes and to use 'final' as the means of controlling inheritance/overriding that it has always been.

IMO, it is 'open' that is superfluous to requirements.

···

Le 21 févr. 2017 à 10:28, Slava Pestov <spestov@apple.com> a écrit :

There is one important difference, but it is rather obscure. ‘final’ allows a class to conform to protocols where ’Self’ appears in invariant position in requirements. For example, say you have the following:


Also worth noting that removing ‘final’ from a class is going to be an ABI breaking change (and source compatibility too), whereas changing a ‘public’ class to ‘open’ poses no such difficulty.

I might be in favor of a proposal to just remove ‘final’ altogether, though, leaving us with just open and public. I’m not sure how much the ability for classes to conform to such protocols matters in practice.

--
Joanna Carter
Carter Consulting

Firstly, let me apologise for any hurt caused, but it is quite difficult to carry on with you own projects *and* keep track of everything that is going on is Swift Evolution, especially with the current mailing list format, with interminable repeat quoting of whole threads in a single digest email.

Now, if it was decided that non-inheritable would be the default for classes :

1. that's only true for inheritance outside of a module

2. why leave 'final' in place (apart from Slava's reasons)?

3. if inheritance of classes, which is a form of extension, is restricted outside of a module, why are extensions of a type allowed without restriction ?

Not forgetting that this discussion was started by me as part of a wider discussion of visibility and extensibility specifiers in general :-)

···

Le 21 févr. 2017 à 12:02, Brent Royal-Gordon <brent@architechies.com> a écrit :

On Feb 20, 2017, at 8:47 AM, Joanna Carter via swift-evolution <swift-evolution@swift.org> wrote:

When it comes to visibilities on classes, why, oh why do we have public vs open *as well as*
the option of marking stuff as final?

We had an enormous, weeks-long, *hugely* contentious debate about whether to introduce `open`, and the end result was that SE-0117 was revised several times and finally approved. It describes the rationale concisely, but pretty well: <https://github.com/apple/swift-evolution/blob/master/proposals/0117-non-public-subclassable-by-default.md&gt;

It doesn't *specifically* address why `final` was kept as well, but essentially, as the Motivation section describes, we wanted non-inheritable to be the default for public classes, so developers would have to specifically choose to open their classes to public subclassing. That meant that having `public` make the class subclassable would not fulfill our goals.

Look. It's not forbidden to re-litigate old design decisions, but if you're going to do it, you should at least study the original proposal and be prepared to either attack flaws in the Motivation section or show why the Proposed Design does not address the problem. Preferably, you should base your argument knowledge from later experience--things we did not know when we reviewed the proposal. You're not saying anything in this thread that wasn't said over and over again in a series of sprawling, stressful near-flamewars last summer.

Please don't tear open old wounds unless you at least have a new treatment to try.

--
Joanna Carter
Carter Consulting

I've thought about how to deal with override in a way that is consistent
with the language. Maybe something like this?

// publicly visible but can't be subclassed.
public private(subclass)

// publicly visible and may be subclasses within the module. The default
public internal(subclass)

// publicly visible and may be subclasses by all.
public public(subclass)

We also can not forget how it apples to methods

public private(override)
public internal(override)
public public(override)

···

On Mon, Feb 20, 2017 at 2:12 PM Joanna Carter via swift-evolution < swift-evolution@swift.org> wrote:

> Le 20 févr. 2017 à 19:18, Dimitri Racordon <Dimitri.Racordon@unige.ch> > a écrit :
>
> Sorry I pressed the wrong button, and the mail was sent right away.
> I was about to add that I could give it a try, or offer my help.

Since I still haven't worked out how to submit a proposal, if you know how
to, maybe you should take the lead.

If you want to contact me offline during the preparation, please feel free

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

Now, if it was decided that non-inheritable would be the default for classes :

1. that's only true for inheritance outside of a module

Yes. As SE-0117 explains, the danger of subclassing is that, if the author of the superclass doesn't expect it and design for it, the subclass can accidentally interfere with the superclass's normal operation. It was felt that this problem is most acute with public classes, where potential subclass authors often have little relationship to the superclass's author and may not have access to the superclass's source code at all. Therefore, as a pragmatic trade-off between safety and convenience, subclassing is permitted by default except for `public` classes.

2. why leave 'final' in place (apart from Slava's reasons)?

There were a number of minor reasons like Slava's, but ultimately, it was felt that `final` is helpful both for non-`public` classes (where it documents that the class is never intended to be subclassed) and for `public` APIs (where it documents that there are no non-`public` subclasses, that there will never *be* non-`public` subclasses in later versions of the library, and that therefore method calls can be made statically).

3. if inheritance of classes, which is a form of extension, is restricted outside of a module, why are extensions of a type allowed without restriction ?

Again, this was explained in SE-0117. Extensions cannot override anything (or access anything about the class that isn't publicly available, since we don't have the `extensible` modifier you proposed), so there's no danger that an extension could interfere with the normal operation of the class. That's not true for subclasses, which can override superclass behavior and change it.

···

On Feb 21, 2017, at 3:15 AM, Joanna Carter <joanna@carterconsulting.org.uk> wrote:

--
Brent Royal-Gordon
Architechies

There is one important difference, but it is rather obscure. ‘final’ allows a class to conform to protocols where ’Self’ appears in invariant position in requirements. For example, say you have the following:


Also worth noting that removing ‘final’ from a class is going to be an ABI breaking change (and source compatibility too), whereas changing a ‘public’ class to ‘open’ poses no such difficulty.

I might be in favor of a proposal to just remove ‘final’ altogether, though, leaving us with just open and public. I’m not sure how much the ability for classes to conform to such protocols matters in practice.

I am not advocating removing 'final' from the language ; rather of removing 'open', which is "foreign" to anyone coming from any other language.

C# has a very similar concept of sealed members. In C++, members cannot be overrided unless they are declared virtual.

C++ however lets you declare the same member in a subclass without it being used by superclass members or when invoked as the super type - this is mostly because code often don’t use polymorphism in C++ due to the performance and memory impact.

My suggestion was to revert 'open' back to 'public' for visibility purposes and to use 'final' as the means of controlling inheritance/overriding that it has always been.

I’m not sure if you mean only controlling overridability at the type level, or defaulting to overridable. I can make strong counterarguments for retaining current behavior in both cases.

IMO, it is 'open' that is superfluous to requirements.

Open is not about requirements. Open is about maintaining invariance of state and proper thread safety as required by the implementation of the superclass.

If the goal isn’t to work within the bounds of a superclass implementation, protocols are a much more appropriate way to describe requirements

-DW

···

On Feb 21, 2017, at 3:47 AM, Joanna Carter via swift-evolution <swift-evolution@swift.org> wrote:

Le 21 févr. 2017 à 10:28, Slava Pestov <spestov@apple.com> a écrit :

When it comes to visibilities on classes, why, oh why do we have public vs open *as well as*
the option of marking stuff as final?

We had an enormous, weeks-long, *hugely* contentious debate about whether to introduce `open`, and the end result was that SE-0117 was revised several times and finally approved. It describes the rationale concisely, but pretty well: <https://github.com/apple/swift-evolution/blob/master/proposals/0117-non-public-subclassable-by-default.md&gt;

It doesn't *specifically* address why `final` was kept as well, but essentially, as the Motivation section describes, we wanted non-inheritable to be the default for public classes, so developers would have to specifically choose to open their classes to public subclassing. That meant that having `public` make the class subclassable would not fulfill our goals.

Look. It's not forbidden to re-litigate old design decisions, but if you're going to do it, you should at least study the original proposal and be prepared to either attack flaws in the Motivation section or show why the Proposed Design does not address the problem. Preferably, you should base your argument knowledge from later experience--things we did not know when we reviewed the proposal. You're not saying anything in this thread that wasn't said over and over again in a series of sprawling, stressful near-flamewars last summer.

Please don't tear open old wounds unless you at least have a new treatment to try.

Firstly, let me apologise for any hurt caused, but it is quite difficult to carry on with you own projects *and* keep track of everything that is going on is Swift Evolution, especially with the current mailing list format, with interminable repeat quoting of whole threads in a single digest email.

Now, if it was decided that non-inheritable would be the default for classes :

1. that's only true for inheritance outside of a module

I think that’s what he meant.

2. why leave 'final' in place (apart from Slava's reasons)?

It’s debatable, and if something is worth considering for removal its final. I’ve asked that exact question last month in the "final + lazy + fileprivate modifiers" thread got some interesting counter arguments:

Matthew Johnson:
My experience is that it is a very useful communication of intent to future readers of the code.
That aside, I think the criteria for a change are different now. Your criteria were relevant during the big breaking change era of Swift 3. I think the criteria for removing a feature at this point should be: is it causing problems that justify the breaking change required to remove it?

Charlie Monroe:
To me, it's useful a lot. The module doesn't necessarily be a 1KLOC framework - I've been recently refactoring a 90KLOC module and the final keyword was fairly useful since some subclasses used hacks by overriding some vars or methods. This allowed me to look at it from a different perspecitve, make some members final and create better API endpoints for customization.
Not to mention that it allows the compiler to access stored properties directly when they're final - if I recall correctly someone from the core team mentioning that.

Derrik Ho:
I find the final keyword useful when I want to communicate that this class should not be subclassed.
I think the behavior should remain the same since it is useful.

3. if inheritance of classes, which is a form of extension, is restricted outside of a module, why are extensions of a type allowed without restriction ?

Because extensions don’t have the same pitfalls as subclassing. The Motivation section of the proposal that introduced open that Brent linked has a very detailed explanations of the pitfalls of subclassing.

···

On 21 Feb 2017, at 12:15, Joanna Carter via swift-evolution <swift-evolution@swift.org> wrote:

Le 21 févr. 2017 à 12:02, Brent Royal-Gordon <brent@architechies.com> a écrit :

On Feb 20, 2017, at 8:47 AM, Joanna Carter via swift-evolution <swift-evolution@swift.org> wrote:

Not forgetting that this discussion was started by me as part of a wider discussion of visibility and extensibility specifiers in general :-)

--
Joanna Carter
Carter Consulting

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

The main problem I see with such naming is that, by the use of the word 'subclass', it implies this is about dealing only with classes.

The reality of the Swift world is that it is no longer just classes that are extensible (by subclassing) but, also, extensions that can be written against any type.

Personally, I still balk at the idea of bracketed visibility specifiers.

···

Le 21 févr. 2017 à 02:25, Derrick Ho <wh1pch81n@gmail.com> a écrit :

I've thought about how to deal with override in a way that is consistent with the language. Maybe something like this?

// publicly visible but can't be subclassed.
public private(subclass)

// publicly visible and may be subclasses within the module. The default
public internal(subclass)

// publicly visible and may be subclasses by all.
public public(subclass)

We also can not forget how it apples to methods

public private(override)
public internal(override)
public public(override)

--
Joanna Carter
Carter Consulting

>
>
>>
>> There is one important difference, but it is rather obscure. ‘final’
allows a class to conform to protocols where ’Self’ appears in invariant
position in requirements. For example, say you have the following:
>>
>> …
>> Also worth noting that removing ‘final’ from a class is going to be an
ABI breaking change (and source compatibility too), whereas changing a
‘public’ class to ‘open’ poses no such difficulty.
>>
>> I might be in favor of a proposal to just remove ‘final’ altogether,
though, leaving us with just open and public. I’m not sure how much the
ability for classes to conform to such protocols matters in practice.
>
> I am not advocating removing 'final' from the language ; rather of
removing 'open', which is "foreign" to anyone coming from any other
language.

C# has a very similar concept of sealed members. In C++, members cannot be
overrided unless they are declared virtual.

C++ however lets you declare the same member in a subclass without it
being used by superclass members or when invoked as the super type - this
is mostly because code often don’t use polymorphism in C++ due to the
performance and memory impact.

Doesn't Kotlin have `open`? I believe it's used slightly differently, but
from the perspective of a user of a third-party library I think the effect
is the same in both languages.

···

On Tue, Feb 21, 2017 at 1:20 PM, David Waite via swift-evolution < swift-evolution@swift.org> wrote:

> On Feb 21, 2017, at 3:47 AM, Joanna Carter via swift-evolution < > swift-evolution@swift.org> wrote:
>> Le 21 févr. 2017 à 10:28, Slava Pestov <spestov@apple.com> a écrit :

My suggestion was to revert 'open' back to 'public' for visibility
purposes and to use 'final' as the means of controlling
inheritance/overriding that it has always been.

I’m not sure if you mean only controlling overridability at the type
level, or defaulting to overridable. I can make strong counterarguments for
retaining current behavior in both cases.

>
> IMO, it is 'open' that is superfluous to requirements.

Open is not about requirements. Open is about maintaining invariance of
state and proper thread safety as required by the implementation of the
superclass.

If the goal isn’t to work within the bounds of a superclass
implementation, protocols are a much more appropriate way to describe
requirements

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

The reality of the Swift world is that it is no longer just classes that are extensible (by subclassing) but, also, extensions that can be written against any type.

I totally agree with that.

It’s actually something that bothers me with the open access modifier. It introduces an asymmetry on the language and emphasis on classes, while I think Swift do its best not to.

···

On 21 Feb 2017, at 09:09, Joanna Carter <joanna@carterconsulting.org.uk<mailto:joanna@carterconsulting.org.uk>> wrote: