[Proposal] Sealed classes by default


(Javier Soto) #1

Hello!

I sent this as a PR <https://github.com/apple/swift-evolution/pull/376> on
the swift-evolution repo, but we never had any discussion about it on-list,
besides a long time ago
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/9702/focus=9708>.
Here's the first draft of the proposal:

Sealed classes by default
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#introduction>
Introduction

Introduce a new sealed class modifier that makes classes and methods
final outside
of the module they're declared in, but non-final within the module.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#motivation>
Motivation

   - It is not uncommon to have a need for a reference type without needing
   inheritance. Classes must be intentionally designed to be subclassable,
   carefully deciding which methods are the override entry-points such that
   the the behavior remains correct and subclasses respect the Liskov
   substitution principle
   <https://en.wikipedia.org/wiki/Liskov_substitution_principle>.
   - Defaulting to non-final allows the author of a class to accidentally
   leave the visible methods open for overrides, even if they didn't carefully
   consider this possibility.
   - Requiring that the author of a class mark a class as open is akin to
   requiring symbols to be explicitly public: it ensures that a conscious
   decision is made regarding whether the ability to subclass a class is
   part of the API.

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#proposed-solution>Proposed
solution

   - New sealed (*actual name pending bike-shedding*) class modifier for
   classes and methods which marks them as only overridable within the module
   they're declared in.
   - sealed becomes the default for classes and methods.
   - New open (*actual name pending bike-shedding*) class modifier to
   explicitly mark a class or a method as overridable.

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#detailed-design>Detailed
design

Code Examples:

/// ModuleA:
/// This class is `sealed` by default./// This is equivalent to
`sealed class SealedParentClass`class SealedParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// This raises a compilation error: a method can't have a "subclassability"
    /// level higher than that of its class.
    open func bar()

    /// The behavior of `final` methods remains unchanged.
    final func baz()
}

open class OpenParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// Overridable methods in an `open` class must be explicitly
marked as `open`.
    open func bar()

    /// The behavior of a `final` method remains unchanged.
    final func baz()
}
/// The behavior of `final` classes remains unchanged.final class FinalClass { }

/// ModuleB:
import ModuleA
/// This raises a compilation error: ParentClass is effectively
`final` from/// this module's point of view.class SubclassA :
SealedParentClass { }
/// This is allowed since `OpenParentClass` has been marked explicitly
`open`class SubclassB : OpenParentClass {
    /// This raises a compilation error: `OpenParentClass.foo` is
    /// effectively `final` outside of `ModuleA`.
    override func foo() { }

    /// This is allowed since `OpenParentClass.bar` is explicitly `open`.
    override func bar() { }
}

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#impact-on-existing-code>Impact
on existing code

   - This would be a backwards-breaking change for all classes and methods
   that are public and non-final, which code outside of their module has
   overriden. Those classes/methods would fail to compile. Their superclass
   would need to be changed to open.

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#alternatives-considered>Alternatives
considered

   - Defaulting to final instead: This would be comparable to Swift
   defaulting to private, as opposed to internal. Just like internal is a
   better trade-off, sealed by default also makes sure that getting started
   with Swift, writing code within a module, doesn't require a lot of
   boilerplate, and fighting against the compiler.

···

--
Javier Soto


(Michael Ilseman) #2

Could you elaborate on how we should treat classes imported from Objective-C or CF-style C? That is, do we always annotate them as being “open” because those paradigms permit subclassing anywhere, or do you propose some kind of recommended “sealed” audit, or what?

···

On Jun 27, 2016, at 3:40 PM, Javier Soto via swift-evolution <swift-evolution@swift.org> wrote:

Hello!

I sent this as a PR <https://github.com/apple/swift-evolution/pull/376> on the swift-evolution repo, but we never had any discussion about it on-list, besides a long time ago <http://thread.gmane.org/gmane.comp.lang.swift.evolution/9702/focus=9708>. Here's the first draft of the proposal:

Sealed classes by default

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#introduction>Introduction

Introduce a new sealed class modifier that makes classes and methods final outside of the module they're declared in, but non-final within the module.

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#motivation>Motivation

It is not uncommon to have a need for a reference type without needing inheritance. Classes must be intentionally designed to be subclassable, carefully deciding which methods are the override entry-points such that the the behavior remains correct and subclasses respect the Liskov substitution principle <https://en.wikipedia.org/wiki/Liskov_substitution_principle>.
Defaulting to non-final allows the author of a class to accidentally leave the visible methods open for overrides, even if they didn't carefully consider this possibility.
Requiring that the author of a class mark a class as open is akin to requiring symbols to be explicitly public: it ensures that a conscious decision is made regarding whether the ability to subclass a class is part of the API.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#proposed-solution>Proposed solution

New sealed (actual name pending bike-shedding) class modifier for classes and methods which marks them as only overridable within the module they're declared in.
sealed becomes the default for classes and methods.
New open (actual name pending bike-shedding) class modifier to explicitly mark a class or a method as overridable.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#detailed-design>Detailed design

Code Examples:

/// ModuleA:

/// This class is `sealed` by default.
/// This is equivalent to `sealed class SealedParentClass`
class SealedParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// This raises a compilation error: a method can't have a "subclassability"
    /// level higher than that of its class.
    open func bar()

    /// The behavior of `final` methods remains unchanged.
    final func baz()
}

open class OpenParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// Overridable methods in an `open` class must be explicitly marked as `open`.
    open func bar()

    /// The behavior of a `final` method remains unchanged.
    final func baz()
}

/// The behavior of `final` classes remains unchanged.
final class FinalClass { }
/// ModuleB:

import ModuleA

/// This raises a compilation error: ParentClass is effectively `final` from
/// this module's point of view.
class SubclassA : SealedParentClass { }

/// This is allowed since `OpenParentClass` has been marked explicitly `open`
class SubclassB : OpenParentClass {
    /// This raises a compilation error: `OpenParentClass.foo` is
    /// effectively `final` outside of `ModuleA`.
    override func foo() { }

    /// This is allowed since `OpenParentClass.bar` is explicitly `open`.
    override func bar() { }
}
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#impact-on-existing-code>Impact on existing code

This would be a backwards-breaking change for all classes and methods that are public and non-final, which code outside of their module has overriden. Those classes/methods would fail to compile. Their superclass would need to be changed to open.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#alternatives-considered>Alternatives considered

Defaulting to final instead: This would be comparable to Swift defaulting to private, as opposed to internal. Just like internal is a better trade-off, sealed by default also makes sure that getting started with Swift, writing code within a module, doesn't require a lot of boilerplate, and fighting against the compiler.
--
Javier Soto
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Javier Soto) #3

That is a very good point, it should be explicitly mentioned in the
proposal. My thought would be that since in the Obj-C runtime it's not
possible to guarantee a class won't have subclasses, or that a method is
not overriden, Obj-C classes would be imported as open.

On the Swift side, I think today it's possible to declare a "public final
@objc class", but you can still inherit from it from Obj-C, right? My hunch
would be that that should be disallowed, but perhaps there's a reason why
it's allowed today.

···

On Mon, Jun 27, 2016 at 4:25 PM Michael Ilseman <milseman@apple.com> wrote:

Could you elaborate on how we should treat classes imported from
Objective-C or CF-style C? That is, do we always annotate them as being
“open” because those paradigms permit subclassing anywhere, or do you
propose some kind of recommended “sealed” audit, or what?

On Jun 27, 2016, at 3:40 PM, Javier Soto via swift-evolution < > swift-evolution@swift.org> wrote:

Hello!

I sent this as a PR <https://github.com/apple/swift-evolution/pull/376>
on the swift-evolution repo, but we never had any discussion about it
on-list, besides a long time ago
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/9702/focus=9708>.
Here's the first draft of the proposal:

Sealed classes by default
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#introduction>
Introduction

Introduce a new sealed class modifier that makes classes and methods final
outside of the module they're declared in, but non-final within the
module.

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#motivation>
Motivation

   - It is not uncommon to have a need for a reference type without
   needing inheritance. Classes must be intentionally designed to be
   subclassable, carefully deciding which methods are the override
   entry-points such that the the behavior remains correct and subclasses
   respect the Liskov substitution principle
   <https://en.wikipedia.org/wiki/Liskov_substitution_principle>.
   - Defaulting to non-final allows the author of a class to accidentally
   leave the visible methods open for overrides, even if they didn't carefully
   consider this possibility.
   - Requiring that the author of a class mark a class as open is akin to
   requiring symbols to be explicitly public: it ensures that a conscious
   decision is made regarding whether the ability to subclass a class is
   part of the API.

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#proposed-solution>Proposed
solution

   - New sealed (*actual name pending bike-shedding*) class modifier for
   classes and methods which marks them as only overridable within the module
   they're declared in.
   - sealed becomes the default for classes and methods.
   - New open (*actual name pending bike-shedding*) class modifier to
   explicitly mark a class or a method as overridable.

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#detailed-design>Detailed
design

Code Examples:

/// ModuleA:
/// This class is `sealed` by default./// This is equivalent to `sealed class SealedParentClass`class SealedParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// This raises a compilation error: a method can't have a "subclassability"
    /// level higher than that of its class.
    open func bar()

    /// The behavior of `final` methods remains unchanged.
    final func baz()
}

open class OpenParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// Overridable methods in an `open` class must be explicitly marked as `open`.
    open func bar()

    /// The behavior of a `final` method remains unchanged.
    final func baz()
}
/// The behavior of `final` classes remains unchanged.final class FinalClass { }

/// ModuleB:
import ModuleA
/// This raises a compilation error: ParentClass is effectively `final` from/// this module's point of view.class SubclassA : SealedParentClass { }
/// This is allowed since `OpenParentClass` has been marked explicitly `open`class SubclassB : OpenParentClass {
    /// This raises a compilation error: `OpenParentClass.foo` is
    /// effectively `final` outside of `ModuleA`.
    override func foo() { }

    /// This is allowed since `OpenParentClass.bar` is explicitly `open`.
    override func bar() { }
}

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#impact-on-existing-code>Impact
on existing code

   - This would be a backwards-breaking change for all classes and
   methods that are public and non-final, which code outside of their module
   has overriden. Those classes/methods would fail to compile. Their
   superclass would need to be changed to open.

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#alternatives-considered>Alternatives
considered

   - Defaulting to final instead: This would be comparable to Swift
   defaulting to private, as opposed to internal. Just like internal is a
   better trade-off, sealed by default also makes sure that getting
   started with Swift, writing code within a module, doesn't require a lot of
   boilerplate, and fighting against the compiler.

--
Javier Soto

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

--

Javier Soto


(Anton Zhilin) #4

Does `sealed` allow for any optimizations? Maybe somehow devirtualizing
method calls?


(Haravikk) #5

I'm a tentative +1, but I think we might consider a degree of "sealing", e.g- make extending the type a warning rather than an error, or require an attribute in order to force the extension. In other words, we make it perfectly clear that extending anyway is a bad idea, but still allow it to be done in cases where code wasn't properly defined with this in mind. Perhaps we could consider something like sealed(warning) and sealed(error), with the former being the default?

···

On 27 Jun 2016, at 23:40, Javier Soto via swift-evolution <swift-evolution@swift.org> wrote:

Hello!

I sent this as a PR <https://github.com/apple/swift-evolution/pull/376> on the swift-evolution repo, but we never had any discussion about it on-list, besides a long time ago <http://thread.gmane.org/gmane.comp.lang.swift.evolution/9702/focus=9708>. Here's the first draft of the proposal:

Sealed classes by default

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#introduction>Introduction

Introduce a new sealed class modifier that makes classes and methods final outside of the module they're declared in, but non-final within the module.

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#motivation>Motivation

It is not uncommon to have a need for a reference type without needing inheritance. Classes must be intentionally designed to be subclassable, carefully deciding which methods are the override entry-points such that the the behavior remains correct and subclasses respect the Liskov substitution principle <https://en.wikipedia.org/wiki/Liskov_substitution_principle>.
Defaulting to non-final allows the author of a class to accidentally leave the visible methods open for overrides, even if they didn't carefully consider this possibility.
Requiring that the author of a class mark a class as open is akin to requiring symbols to be explicitly public: it ensures that a conscious decision is made regarding whether the ability to subclass a class is part of the API.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#proposed-solution>Proposed solution

New sealed (actual name pending bike-shedding) class modifier for classes and methods which marks them as only overridable within the module they're declared in.
sealed becomes the default for classes and methods.
New open (actual name pending bike-shedding) class modifier to explicitly mark a class or a method as overridable.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#detailed-design>Detailed design

Code Examples:

/// ModuleA:

/// This class is `sealed` by default.
/// This is equivalent to `sealed class SealedParentClass`
class SealedParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// This raises a compilation error: a method can't have a "subclassability"
    /// level higher than that of its class.
    open func bar()

    /// The behavior of `final` methods remains unchanged.
    final func baz()
}

open class OpenParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// Overridable methods in an `open` class must be explicitly marked as `open`.
    open func bar()

    /// The behavior of a `final` method remains unchanged.
    final func baz()
}

/// The behavior of `final` classes remains unchanged.
final class FinalClass { }
/// ModuleB:

import ModuleA

/// This raises a compilation error: ParentClass is effectively `final` from
/// this module's point of view.
class SubclassA : SealedParentClass { }

/// This is allowed since `OpenParentClass` has been marked explicitly `open`
class SubclassB : OpenParentClass {
    /// This raises a compilation error: `OpenParentClass.foo` is
    /// effectively `final` outside of `ModuleA`.
    override func foo() { }

    /// This is allowed since `OpenParentClass.bar` is explicitly `open`.
    override func bar() { }
}
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#impact-on-existing-code>Impact on existing code

This would be a backwards-breaking change for all classes and methods that are public and non-final, which code outside of their module has overriden. Those classes/methods would fail to compile. Their superclass would need to be changed to open.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#alternatives-considered>Alternatives considered

Defaulting to final instead: This would be comparable to Swift defaulting to private, as opposed to internal. Just like internal is a better trade-off, sealed by default also makes sure that getting started with Swift, writing code within a module, doesn't require a lot of boilerplate, and fighting against the compiler.
--
Javier Soto
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(David Rönnqvist) #6

All bike-shedding aside, I see two parts of this proposal and I come down on different sides for the two.

1. Introducing a new class modifier that acts as final outside the defining module
2. Changing the default to this new modifier (and thus also introducing a third explicit class modifier that represents the current default (non-final) behavior.

I think that the behavior of the new proposed modifier is useful. I imagine that it would allow for the same type of optimizations as a final class (assuming whole module optimizations) while remaining flexible within the module itself. We’re currently using a public protocol with one or more internal non-final classes to achieve similar results in the specific scenario where we want a unified external type.

On the topic of changing the default, I’m against for the same reasons that was brought up in the discussion of making final the default. Since those reasons were mostly about usage outside of the same module, I find them equally valid in this case.

- David

···

On 28 Jun 2016, at 00:40, Javier Soto via swift-evolution <swift-evolution@swift.org> wrote:

Hello!

I sent this as a PR <https://github.com/apple/swift-evolution/pull/376> on the swift-evolution repo, but we never had any discussion about it on-list, besides a long time ago <http://thread.gmane.org/gmane.comp.lang.swift.evolution/9702/focus=9708>. Here's the first draft of the proposal:

Sealed classes by default

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#introduction>Introduction

Introduce a new sealed class modifier that makes classes and methods final outside of the module they're declared in, but non-final within the module.

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#motivation>Motivation

It is not uncommon to have a need for a reference type without needing inheritance. Classes must be intentionally designed to be subclassable, carefully deciding which methods are the override entry-points such that the the behavior remains correct and subclasses respect the Liskov substitution principle <https://en.wikipedia.org/wiki/Liskov_substitution_principle>.
Defaulting to non-final allows the author of a class to accidentally leave the visible methods open for overrides, even if they didn't carefully consider this possibility.
Requiring that the author of a class mark a class as open is akin to requiring symbols to be explicitly public: it ensures that a conscious decision is made regarding whether the ability to subclass a class is part of the API.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#proposed-solution>Proposed solution

New sealed (actual name pending bike-shedding) class modifier for classes and methods which marks them as only overridable within the module they're declared in.
sealed becomes the default for classes and methods.
New open (actual name pending bike-shedding) class modifier to explicitly mark a class or a method as overridable.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#detailed-design>Detailed design

Code Examples:

/// ModuleA:

/// This class is `sealed` by default.
/// This is equivalent to `sealed class SealedParentClass`
class SealedParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// This raises a compilation error: a method can't have a "subclassability"
    /// level higher than that of its class.
    open func bar()

    /// The behavior of `final` methods remains unchanged.
    final func baz()
}

open class OpenParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// Overridable methods in an `open` class must be explicitly marked as `open`.
    open func bar()

    /// The behavior of a `final` method remains unchanged.
    final func baz()
}

/// The behavior of `final` classes remains unchanged.
final class FinalClass { }
/// ModuleB:

import ModuleA

/// This raises a compilation error: ParentClass is effectively `final` from
/// this module's point of view.
class SubclassA : SealedParentClass { }

/// This is allowed since `OpenParentClass` has been marked explicitly `open`
class SubclassB : OpenParentClass {
    /// This raises a compilation error: `OpenParentClass.foo` is
    /// effectively `final` outside of `ModuleA`.
    override func foo() { }

    /// This is allowed since `OpenParentClass.bar` is explicitly `open`.
    override func bar() { }
}
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#impact-on-existing-code>Impact on existing code

This would be a backwards-breaking change for all classes and methods that are public and non-final, which code outside of their module has overriden. Those classes/methods would fail to compile. Their superclass would need to be changed to open.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#alternatives-considered>Alternatives considered

Defaulting to final instead: This would be comparable to Swift defaulting to private, as opposed to internal. Just like internal is a better trade-off, sealed by default also makes sure that getting started with Swift, writing code within a module, doesn't require a lot of boilerplate, and fighting against the compiler.
--
Javier Soto
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(David Sweeris) #7

+1 for the concept of a "sealed” class.
-1 for making it default.

Would there be a benefit to having “sealed" protocols, as well?

- Dave Sweeris

···

On Jun 27, 2016, at 17:40, Javier Soto via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello!

I sent this as a PR <https://github.com/apple/swift-evolution/pull/376> on the swift-evolution repo, but we never had any discussion about it on-list, besides a long time ago <http://thread.gmane.org/gmane.comp.lang.swift.evolution/9702/focus=9708>. Here's the first draft of the proposal:

Sealed classes by default

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#introduction>Introduction

Introduce a new sealed class modifier that makes classes and methods final outside of the module they're declared in, but non-final within the module.

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#motivation>Motivation

It is not uncommon to have a need for a reference type without needing inheritance. Classes must be intentionally designed to be subclassable, carefully deciding which methods are the override entry-points such that the the behavior remains correct and subclasses respect the Liskov substitution principle <https://en.wikipedia.org/wiki/Liskov_substitution_principle>.
Defaulting to non-final allows the author of a class to accidentally leave the visible methods open for overrides, even if they didn't carefully consider this possibility.
Requiring that the author of a class mark a class as open is akin to requiring symbols to be explicitly public: it ensures that a conscious decision is made regarding whether the ability to subclass a class is part of the API.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#proposed-solution>Proposed solution

New sealed (actual name pending bike-shedding) class modifier for classes and methods which marks them as only overridable within the module they're declared in.
sealed becomes the default for classes and methods.
New open (actual name pending bike-shedding) class modifier to explicitly mark a class or a method as overridable.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#detailed-design>Detailed design

Code Examples:

/// ModuleA:

/// This class is `sealed` by default.
/// This is equivalent to `sealed class SealedParentClass`
class SealedParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// This raises a compilation error: a method can't have a "subclassability"
    /// level higher than that of its class.
    open func bar()

    /// The behavior of `final` methods remains unchanged.
    final func baz()
}

open class OpenParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// Overridable methods in an `open` class must be explicitly marked as `open`.
    open func bar()

    /// The behavior of a `final` method remains unchanged.
    final func baz()
}

/// The behavior of `final` classes remains unchanged.
final class FinalClass { }
/// ModuleB:

import ModuleA

/// This raises a compilation error: ParentClass is effectively `final` from
/// this module's point of view.
class SubclassA : SealedParentClass { }

/// This is allowed since `OpenParentClass` has been marked explicitly `open`
class SubclassB : OpenParentClass {
    /// This raises a compilation error: `OpenParentClass.foo` is
    /// effectively `final` outside of `ModuleA`.
    override func foo() { }

    /// This is allowed since `OpenParentClass.bar` is explicitly `open`.
    override func bar() { }
}
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#impact-on-existing-code>Impact on existing code

This would be a backwards-breaking change for all classes and methods that are public and non-final, which code outside of their module has overriden. Those classes/methods would fail to compile. Their superclass would need to be changed to open.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#alternatives-considered>Alternatives considered

Defaulting to final instead: This would be comparable to Swift defaulting to private, as opposed to internal. Just like internal is a better trade-off, sealed by default also makes sure that getting started with Swift, writing code within a module, doesn't require a lot of boilerplate, and fighting against the compiler.
--
Javier Soto
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Michael Ilseman) #8

I was also referring to how we present Objective-C classes in Swift. That is, if a Swift user tries to subclass an Objective-C-imported class, then we’d take into account sealed-ness in order to issue an error/warning, etc. If you are also proposing a Clang attribute for this, e.g. ‘swift_sealed’, to import as sealed (meaning issue an error if Swift users try to subclass it), then that should be spelled out as well. I don’t have an opinion on whether this is a good idea yet, just pointing out some more directions to explore. In general it feels like your proposal could use more fleshing out.

···

On Jun 27, 2016, at 5:08 PM, Javier Soto <javier.api@gmail.com> wrote:

That is a very good point, it should be explicitly mentioned in the proposal. My thought would be that since in the Obj-C runtime it's not possible to guarantee a class won't have subclasses, or that a method is not overriden, Obj-C classes would be imported as open.

On the Swift side, I think today it's possible to declare a "public final @objc class", but you can still inherit from it from Obj-C, right? My hunch would be that that should be disallowed, but perhaps there's a reason why it's allowed today.
On Mon, Jun 27, 2016 at 4:25 PM Michael Ilseman <milseman@apple.com <mailto:milseman@apple.com>> wrote:
Could you elaborate on how we should treat classes imported from Objective-C or CF-style C? That is, do we always annotate them as being “open” because those paradigms permit subclassing anywhere, or do you propose some kind of recommended “sealed” audit, or what?

On Jun 27, 2016, at 3:40 PM, Javier Soto via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello!

I sent this as a PR <https://github.com/apple/swift-evolution/pull/376> on the swift-evolution repo, but we never had any discussion about it on-list, besides a long time ago <http://thread.gmane.org/gmane.comp.lang.swift.evolution/9702/focus=9708>. Here's the first draft of the proposal:

Sealed classes by default

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#introduction>Introduction

Introduce a new sealed class modifier that makes classes and methods final outside of the module they're declared in, but non-final within the module.

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#motivation>Motivation

It is not uncommon to have a need for a reference type without needing inheritance. Classes must be intentionally designed to be subclassable, carefully deciding which methods are the override entry-points such that the the behavior remains correct and subclasses respect the Liskov substitution principle <https://en.wikipedia.org/wiki/Liskov_substitution_principle>.
Defaulting to non-final allows the author of a class to accidentally leave the visible methods open for overrides, even if they didn't carefully consider this possibility.
Requiring that the author of a class mark a class as open is akin to requiring symbols to be explicitly public: it ensures that a conscious decision is made regarding whether the ability to subclass a class is part of the API.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#proposed-solution>Proposed solution

New sealed (actual name pending bike-shedding) class modifier for classes and methods which marks them as only overridable within the module they're declared in.
sealed becomes the default for classes and methods.
New open (actual name pending bike-shedding) class modifier to explicitly mark a class or a method as overridable.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#detailed-design>Detailed design

Code Examples:

/// ModuleA:

/// This class is `sealed` by default.
/// This is equivalent to `sealed class SealedParentClass`
class SealedParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// This raises a compilation error: a method can't have a "subclassability"
    /// level higher than that of its class.
    open func bar()

    /// The behavior of `final` methods remains unchanged.
    final func baz()
}

open class OpenParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// Overridable methods in an `open` class must be explicitly marked as `open`.
    open func bar()

    /// The behavior of a `final` method remains unchanged.
    final func baz()
}

/// The behavior of `final` classes remains unchanged.
final class FinalClass { }
/// ModuleB:

import ModuleA

/// This raises a compilation error: ParentClass is effectively `final` from
/// this module's point of view.
class SubclassA : SealedParentClass { }

/// This is allowed since `OpenParentClass` has been marked explicitly `open`
class SubclassB : OpenParentClass {
    /// This raises a compilation error: `OpenParentClass.foo` is
    /// effectively `final` outside of `ModuleA`.
    override func foo() { }

    /// This is allowed since `OpenParentClass.bar` is explicitly `open`.
    override func bar() { }
}
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#impact-on-existing-code>Impact on existing code

This would be a backwards-breaking change for all classes and methods that are public and non-final, which code outside of their module has overriden. Those classes/methods would fail to compile. Their superclass would need to be changed to open.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#alternatives-considered>Alternatives considered

Defaulting to final instead: This would be comparable to Swift defaulting to private, as opposed to internal. Just like internal is a better trade-off, sealed by default also makes sure that getting started with Swift, writing code within a module, doesn't require a lot of boilerplate, and fighting against the compiler.
--
Javier Soto

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

--
Javier Soto


(L Mihalkovic) #9

-1 for the fact that if all devs can write working code, fewer can do it in a clear structured fashion that is well designed for extensibility. A couple months ago I even ran into difficulties when trying to extend AlamoFire because some things had not been designed as cleanly as they could have been to make extending it easy. So if the default is now that everything becomes non-extensible but default, it is going to complicate (and partially defeat the purpose of) reusing libraries.
Regards
(From mobile)

···

On Jun 28, 2016, at 2:11 AM, Michael Ilseman via swift-evolution <swift-evolution@swift.org> wrote:

I was also referring to how we present Objective-C classes in Swift. That is, if a Swift user tries to subclass an Objective-C-imported class, then we’d take into account sealed-ness in order to issue an error/warning, etc. If you are also proposing a Clang attribute for this, e.g. ‘swift_sealed’, to import as sealed (meaning issue an error if Swift users try to subclass it), then that should be spelled out as well. I don’t have an opinion on whether this is a good idea yet, just pointing out some more directions to explore. In general it feels like your proposal could use more fleshing out.

On Jun 27, 2016, at 5:08 PM, Javier Soto <javier.api@gmail.com> wrote:

That is a very good point, it should be explicitly mentioned in the proposal. My thought would be that since in the Obj-C runtime it's not possible to guarantee a class won't have subclasses, or that a method is not overriden, Obj-C classes would be imported as open.

On the Swift side, I think today it's possible to declare a "public final @objc class", but you can still inherit from it from Obj-C, right? My hunch would be that that should be disallowed, but perhaps there's a reason why it's allowed today.
On Mon, Jun 27, 2016 at 4:25 PM Michael Ilseman <milseman@apple.com> wrote:

Could you elaborate on how we should treat classes imported from Objective-C or CF-style C? That is, do we always annotate them as being “open” because those paradigms permit subclassing anywhere, or do you propose some kind of recommended “sealed” audit, or what?

On Jun 27, 2016, at 3:40 PM, Javier Soto via swift-evolution <swift-evolution@swift.org> wrote:

Hello!

I sent this as a PR on the swift-evolution repo, but we never had any discussion about it on-list, besides a long time ago. Here's the first draft of the proposal:

Sealed classes by default
Introduction

Introduce a new sealed class modifier that makes classes and methods final outside of the module they're declared in, but non-final within the module.

Motivation

It is not uncommon to have a need for a reference type without needing inheritance. Classes must be intentionally designed to be subclassable, carefully deciding which methods are the override entry-points such that the the behavior remains correct and subclasses respect the Liskov substitution principle.
Defaulting to non-final allows the author of a class to accidentally leave the visible methods open for overrides, even if they didn't carefully consider this possibility.
Requiring that the author of a class mark a class as open is akin to requiring symbols to be explicitly public: it ensures that a conscious decision is made regarding whether the ability to subclass a class is part of the API.
Proposed solution

New sealed (actual name pending bike-shedding) class modifier for classes and methods which marks them as only overridable within the module they're declared in.
sealed becomes the default for classes and methods.
New open (actual name pending bike-shedding) class modifier to explicitly mark a class or a method as overridable.
Detailed design

Code Examples:

/// ModuleA:

/// This class is `sealed` by default.
/// This is equivalent to `sealed class SealedParentClass`
class SealedParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// This raises a compilation error: a method can't have a "subclassability"
    /// level higher than that of its class.
    open func bar()

    /// The behavior of `final` methods remains unchanged.
    final func baz()
}

open class OpenParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// Overridable methods in an `open` class must be explicitly marked as `open`.
    open func bar()

    /// The behavior of a `final` method remains unchanged.
    final func baz()
}

/// The behavior of `final` classes remains unchanged.
final class FinalClass { }
/// ModuleB:

import ModuleA

/// This raises a compilation error: ParentClass is effectively `final` from
/// this module's point of view.
class SubclassA : SealedParentClass { }

/// This is allowed since `OpenParentClass` has been marked explicitly `open`
class SubclassB : OpenParentClass {
    /// This raises a compilation error: `OpenParentClass.foo` is
    /// effectively `final` outside of `ModuleA`.
    override func foo() { }

    /// This is allowed since `OpenParentClass.bar` is explicitly `open`.
    override func bar() { }
}
Impact on existing code

This would be a backwards-breaking change for all classes and methods that are public and non-final, which code outside of their module has overriden. Those classes/methods would fail to compile. Their superclass would need to be changed to open.
Alternatives considered

Defaulting to final instead: This would be comparable to Swift defaulting to private, as opposed to internal. Just like internal is a better trade-off, sealed by default also makes sure that getting started with Swift, writing code within a module, doesn't require a lot of boilerplate, and fighting against the compiler.
--
Javier Soto

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

--
Javier Soto

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


(Alejandro Martinez) #10

Anton Zhilin: That is one of the points if I’m not mistaken. Sealed
means that with whole-module-optimization the compiler can optimise
more things as it can treat it as final for other modules.

L. Mihalkovic: Could you give an example of what exactly do you mean?
I know one of the reasons behind the proposal is to actually improve
those situations by forcing us to think more on customisation when
designing APIs.

···

On Tue, Jun 28, 2016 at 12:44 PM, Anton Zhilin via swift-evolution <swift-evolution@swift.org> wrote:

Does `sealed` allow for any optimizations? Maybe somehow devirtualizing
method calls?

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

--
Alejandro Martinez
http://alejandromp.com


(Michael Peternell) #11

Aren't sealed classes already implemented? I think the keyword is `final`..
So there is nothing left to do :slight_smile:

···

Am 29.06.2016 um 15:54 schrieb David Sweeris via swift-evolution <swift-evolution@swift.org>:

+1 for the concept of a "sealed” class.
-1 for making it default.


(Mark Lacey) #12

-1 for the fact that if all devs can write working code, fewer can do it in a clear structured fashion that is well designed for extensibility.

This sounds more like an argument for having sealed classes than not. As the proposal points out in the motivation, if the base class is not designed with subclassing in mind then overriding methods can result in unintended behavior (e.g. crashing, or other bugs).

Mark

···

On Jun 27, 2016, at 9:10 PM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:

A couple months ago I even ran into difficulties when trying to extend AlamoFire because some things had not been designed as cleanly as they could have been to make extending it easy. So if the default is now that everything becomes non-extensible but default, it is going to complicate (and partially defeat the purpose of) reusing libraries.
Regards
(From mobile)

On Jun 28, 2016, at 2:11 AM, Michael Ilseman via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I was also referring to how we present Objective-C classes in Swift. That is, if a Swift user tries to subclass an Objective-C-imported class, then we’d take into account sealed-ness in order to issue an error/warning, etc. If you are also proposing a Clang attribute for this, e.g. ‘swift_sealed’, to import as sealed (meaning issue an error if Swift users try to subclass it), then that should be spelled out as well. I don’t have an opinion on whether this is a good idea yet, just pointing out some more directions to explore. In general it feels like your proposal could use more fleshing out.

On Jun 27, 2016, at 5:08 PM, Javier Soto <javier.api@gmail.com <mailto:javier.api@gmail.com>> wrote:

That is a very good point, it should be explicitly mentioned in the proposal. My thought would be that since in the Obj-C runtime it's not possible to guarantee a class won't have subclasses, or that a method is not overriden, Obj-C classes would be imported as open.

On the Swift side, I think today it's possible to declare a "public final @objc class", but you can still inherit from it from Obj-C, right? My hunch would be that that should be disallowed, but perhaps there's a reason why it's allowed today.
On Mon, Jun 27, 2016 at 4:25 PM Michael Ilseman <milseman@apple.com <mailto:milseman@apple.com>> wrote:
Could you elaborate on how we should treat classes imported from Objective-C or CF-style C? That is, do we always annotate them as being “open” because those paradigms permit subclassing anywhere, or do you propose some kind of recommended “sealed” audit, or what?

On Jun 27, 2016, at 3:40 PM, Javier Soto via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Hello!

I sent this as a PR <https://github.com/apple/swift-evolution/pull/376> on the swift-evolution repo, but we never had any discussion about it on-list, besides a long time ago <http://thread.gmane.org/gmane.comp.lang.swift.evolution/9702/focus=9708>. Here's the first draft of the proposal:

Sealed classes by default

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#introduction>Introduction

Introduce a new sealed class modifier that makes classes and methods final outside of the module they're declared in, but non-final within the module.

<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#motivation>Motivation

It is not uncommon to have a need for a reference type without needing inheritance. Classes must be intentionally designed to be subclassable, carefully deciding which methods are the override entry-points such that the the behavior remains correct and subclasses respect the Liskov substitution principle <https://en.wikipedia.org/wiki/Liskov_substitution_principle>.
Defaulting to non-final allows the author of a class to accidentally leave the visible methods open for overrides, even if they didn't carefully consider this possibility.
Requiring that the author of a class mark a class as open is akin to requiring symbols to be explicitly public: it ensures that a conscious decision is made regarding whether the ability to subclass a class is part of the API.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#proposed-solution>Proposed solution

New sealed (actual name pending bike-shedding) class modifier for classes and methods which marks them as only overridable within the module they're declared in.
sealed becomes the default for classes and methods.
New open (actual name pending bike-shedding) class modifier to explicitly mark a class or a method as overridable.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#detailed-design>Detailed design

Code Examples:

/// ModuleA:

/// This class is `sealed` by default.
/// This is equivalent to `sealed class SealedParentClass`
class SealedParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// This raises a compilation error: a method can't have a "subclassability"
    /// level higher than that of its class.
    open func bar()

    /// The behavior of `final` methods remains unchanged.
    final func baz()
}

open class OpenParentClass {
    /// This method is `sealed` by default`.
    func foo()

    /// Overridable methods in an `open` class must be explicitly marked as `open`.
    open func bar()

    /// The behavior of a `final` method remains unchanged.
    final func baz()
}

/// The behavior of `final` classes remains unchanged.
final class FinalClass { }
/// ModuleB:

import ModuleA

/// This raises a compilation error: ParentClass is effectively `final` from
/// this module's point of view.
class SubclassA : SealedParentClass { }

/// This is allowed since `OpenParentClass` has been marked explicitly `open`
class SubclassB : OpenParentClass {
    /// This raises a compilation error: `OpenParentClass.foo` is
    /// effectively `final` outside of `ModuleA`.
    override func foo() { }

    /// This is allowed since `OpenParentClass.bar` is explicitly `open`.
    override func bar() { }
}
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#impact-on-existing-code>Impact on existing code

This would be a backwards-breaking change for all classes and methods that are public and non-final, which code outside of their module has overriden. Those classes/methods would fail to compile. Their superclass would need to be changed to open.
<https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#alternatives-considered>Alternatives considered

Defaulting to final instead: This would be comparable to Swift defaulting to private, as opposed to internal. Just like internal is a better trade-off, sealed by default also makes sure that getting started with Swift, writing code within a module, doesn't require a lot of boilerplate, and fighting against the compiler.
--
Javier Soto

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

--
Javier Soto

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

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


(L Mihalkovic) #13

Regards
LM
(From mobile)

Anton Zhilin: That is one of the points if I’m not mistaken. Sealed
means that with whole-module-optimization the compiler can optimise
more things as it can treat it as final for other modules.

L. Mihalkovic: Could you give an example of what exactly do you mean?
I know one of the reasons behind the proposal is to actually improve
those situations by forcing us to think more on customisation when
designing APIs.

In many situation it has been my experience that libraries can be extended DESPITE their authors, rather than only thanks to the skills the authors have shown in planning for the future. It is what happened to me with AlamoFire, where i was able to extend it because some cracks existed which let me do something the designers did not think about (to me it was a lack of imagination to not have anticipated what i wanted to do).

So if this can happen with a lib made by very experienced/talented developers, then imagine what happens with far less skilled developers.. it will mean having to copy code in order extend. It may sound pessimistic, but if u had seen as much bad code as i have seen, you might understand the view i am sharing.

What's worse is that objc is not particularly conducive to good software architecture (it is a bit like perl and javascript where anything can be touched from anywhere, and has a limited set of constructs compared to c++, scala, java, c#, swift). So i do not believe that it has prepared objc devs to suddenly become great code designers with a language that has multiples levels of scoping/nesting (i would not use most of the swift libs i have seen on github to teach software design).

Hence my conclusion that defaulting to sealed may be giving too much credit to the code that is currently available for reuse.

···

On Jun 28, 2016, at 1:57 PM, Alejandro Martinez via swift-evolution <swift-evolution@swift.org> wrote:

On Tue, Jun 28, 2016 at 12:44 PM, Anton Zhilin via swift-evolution > <swift-evolution@swift.org> wrote:

Does `sealed` allow for any optimizations? Maybe somehow devirtualizing
method calls?

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

--
Alejandro Martinez
http://alejandromp.com
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(John McCall) #14

Do we really need a new keyword? Since we already have syntax like `internal(set)` couldn't we do `internal(unsealed)`, etc.

The spelling is definitely up for debate. I remember that Chris in particular wasn't happy with "sealed".

(Of course the entire proposal is still up for debate; I'm just saying that so far we've been talking about the proposal at a high level with very little attention to specifics.)

John.

···

On Jun 29, 2016, at 11:11 AM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

On Wed, Jun 29, 2016 at 12:21 PM, David Sweeris via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
> On Jun 29, 2016, at 12:15 PM, Michael Peternell <michael.peternell@gmx.at <mailto:michael.peternell@gmx.at>> wrote:
>
>
>> Am 29.06.2016 um 15:54 schrieb David Sweeris via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:
>>
>> +1 for the concept of a "sealed” class.
>> -1 for making it default.
>
> Aren't sealed classes already implemented? I think the keyword is `final`..
> So there is nothing left to do :slight_smile:

No, `final` doesn’t allow for any subclassing, but `sealed` allows for subclassing within your module (where you can presumably write more efficient code based on knowledge of each subclass).

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

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


(Matthew Johnson) #15

+1 for the concept of a "sealed” class.
-1 for making it default.

Aren't sealed classes already implemented? I think the keyword is `final`..
So there is nothing left to do :slight_smile:

Sealed and final are very different. Sealed allows subclasses *within the declaring module* but final does not allow any subclasses at all.

···

Sent from my iPhone

On Jun 29, 2016, at 12:15 PM, Michael Peternell via swift-evolution <swift-evolution@swift.org> wrote:

Am 29.06.2016 um 15:54 schrieb David Sweeris via swift-evolution <swift-evolution@swift.org>:

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


(David Sweeris) #16

No, `final` doesn’t allow for any subclassing, but `sealed` allows for subclassing within your module (where you can presumably write more efficient code based on knowledge of each subclass).

- Dave Sweeris

···

On Jun 29, 2016, at 12:15 PM, Michael Peternell <michael.peternell@gmx.at> wrote:

Am 29.06.2016 um 15:54 schrieb David Sweeris via swift-evolution <swift-evolution@swift.org>:

+1 for the concept of a "sealed” class.
-1 for making it default.

Aren't sealed classes already implemented? I think the keyword is `final`..
So there is nothing left to do :slight_smile:


(Chéyo Jiménez) #17

I like `closed` better because it would pair up nicely with `opened`

`opened` would be a good keyword imo (applying the ing/ed rule).

In the future if we ever support open enums, we could use the same keyword. :slight_smile:

···

On Jun 29, 2016, at 11:16 AM, John McCall via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 29, 2016, at 11:11 AM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Do we really need a new keyword? Since we already have syntax like `internal(set)` couldn't we do `internal(unsealed)`, etc.

The spelling is definitely up for debate. I remember that Chris in particular wasn't happy with "sealed".

(Of course the entire proposal is still up for debate; I'm just saying that so far we've been talking about the proposal at a high level with very little attention to specifics.)

John.

On Wed, Jun 29, 2016 at 12:21 PM, David Sweeris via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
> On Jun 29, 2016, at 12:15 PM, Michael Peternell <michael.peternell@gmx.at <mailto:michael.peternell@gmx.at>> wrote:
>
>
>> Am 29.06.2016 um 15:54 schrieb David Sweeris via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:
>>
>> +1 for the concept of a "sealed” class.
>> -1 for making it default.
>
> Aren't sealed classes already implemented? I think the keyword is `final`..
> So there is nothing left to do :slight_smile:

No, `final` doesn’t allow for any subclassing, but `sealed` allows for subclassing within your module (where you can presumably write more efficient code based on knowledge of each subclass).

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

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

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


(Xiaodi Wu) #18

Do we really need a new keyword? Since we already have syntax like
`internal(set)` couldn't we do `internal(unsealed)`, etc.

···

On Wed, Jun 29, 2016 at 12:21 PM, David Sweeris via swift-evolution < swift-evolution@swift.org> wrote:

> On Jun 29, 2016, at 12:15 PM, Michael Peternell < > michael.peternell@gmx.at> wrote:
>
>
>> Am 29.06.2016 um 15:54 schrieb David Sweeris via swift-evolution < > swift-evolution@swift.org>:
>>
>> +1 for the concept of a "sealed” class.
>> -1 for making it default.
>
> Aren't sealed classes already implemented? I think the keyword is
`final`..
> So there is nothing left to do :slight_smile:

No, `final` doesn’t allow for any subclassing, but `sealed` allows for
subclassing within your module (where you can presumably write more
efficient code based on knowledge of each subclass).

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


(Michael Peternell) #19

Do you mean `public(unsealed)`? Because `internal(unsealed)` doesn't really make sense. `internal` declarations are always sealed.

-Michael

···

Am 29.06.2016 um 20:11 schrieb Xiaodi Wu via swift-evolution <swift-evolution@swift.org>:

Do we really need a new keyword? Since we already have syntax like `internal(set)` couldn't we do `internal(unsealed)`, etc.

On Wed, Jun 29, 2016 at 12:21 PM, David Sweeris via swift-evolution <swift-evolution@swift.org> wrote:
> On Jun 29, 2016, at 12:15 PM, Michael Peternell <michael.peternell@gmx.at> wrote:
>
>
>> Am 29.06.2016 um 15:54 schrieb David Sweeris via swift-evolution <swift-evolution@swift.org>:
>>
>> +1 for the concept of a "sealed” class.
>> -1 for making it default.
>
> Aren't sealed classes already implemented? I think the keyword is `final`..
> So there is nothing left to do :slight_smile:

No, `final` doesn’t allow for any subclassing, but `sealed` allows for subclassing within your module (where you can presumably write more efficient code based on knowledge of each subclass).

- Dave Sweeris
_______________________________________________
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


(Sean Heber) #20

But I think the counter argument is, what if you need to fix or workaround unintended behavior of the class you’re trying to use?

l8r
Sean

···

On Jun 28, 2016, at 9:52 AM, Mark Lacey via swift-evolution <swift-evolution@swift.org> wrote:

On Jun 27, 2016, at 9:10 PM, L. Mihalkovic via swift-evolution <swift-evolution@swift.org> wrote:

-1 for the fact that if all devs can write working code, fewer can do it in a clear structured fashion that is well designed for extensibility.

This sounds more like an argument for having sealed classes than not. As the proposal points out in the motivation, if the base class is not designed with subclassing in mind then overriding methods can result in unintended behavior (e.g. crashing, or other bugs).