[swift-evolution] [Proposal] Sealed classes by default

Javier Soto javier.api at gmail.com
Mon Jun 27 17:40:18 CDT 2016


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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160627/38d97b8b/attachment.html>


More information about the swift-evolution mailing list