[swift-evolution] [Proposal] Sealed classes by default
Javier Soto
javier.api at gmail.com
Mon Jun 27 19:08:20 CDT 2016
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 at 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 at 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 at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
> --
Javier Soto
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160628/fcdc9e2a/attachment.html>
More information about the swift-evolution
mailing list