[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