<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">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.</div><div class=""><br class=""></div><br class=""><div><blockquote type="cite" class=""><div class="">On Jun 27, 2016, at 5:08 PM, Javier Soto &lt;<a href="mailto:javier.api@gmail.com" class="">javier.api@gmail.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class="">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. <br class=""><br class="">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. <br class=""><div class="gmail_quote"><div dir="ltr" class="">On Mon, Jun 27, 2016 at 4:25 PM Michael Ilseman &lt;<a href="mailto:milseman@apple.com" class="">milseman@apple.com</a>&gt; wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word" class=""><div class="">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?</div><br class=""><div class=""><blockquote type="cite" class=""></blockquote></div></div><div style="word-wrap:break-word" class=""><div class=""><blockquote type="cite" class=""><div class="">On Jun 27, 2016, at 3:40 PM, Javier Soto via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class=""></blockquote></div></div><div style="word-wrap:break-word" class=""><div class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class="">Hello!<div class=""><br class=""></div><div class="">I sent this as a <a href="https://github.com/apple/swift-evolution/pull/376" target="_blank" class="">PR</a> on the swift-evolution repo, but we never had any discussion about it on-list, besides <a href="http://thread.gmane.org/gmane.comp.lang.swift.evolution/9702/focus=9708" target="_blank" class="">a long time ago</a>. Here's the first draft of the proposal:</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><h1 style="font-size:2.25em;margin:0px 0px 16px;line-height:1.2;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:&quot;helvetica neue&quot;,helvetica,&quot;segoe ui&quot;,arial,freesans,sans-serif,&quot;apple color emoji&quot;,&quot;segoe ui emoji&quot;,&quot;segoe ui symbol&quot;" class="">Sealed classes by default</h1><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:&quot;helvetica neue&quot;,helvetica,&quot;segoe ui&quot;,arial,freesans,sans-serif,&quot;apple color emoji&quot;,&quot;segoe ui emoji&quot;,&quot;segoe ui symbol&quot;" class=""><a href="https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#introduction" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent" target="_blank" class=""></a>Introduction</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:&quot;helvetica neue&quot;,helvetica,&quot;segoe ui&quot;,arial,freesans,sans-serif,&quot;apple color emoji&quot;,&quot;segoe ui emoji&quot;,&quot;segoe ui symbol&quot;;font-size:16px;line-height:25.6px" class="">Introduce a new<span class="">&nbsp;</span><code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">sealed</code><span class="">&nbsp;</span>class modifier that makes classes and methods<span class="">&nbsp;</span><code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">final</code><span class="">&nbsp;</span>outside of the module they're declared in, but non-<code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">final</code><span class="">&nbsp;</span>within the module.</p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:&quot;helvetica neue&quot;,helvetica,&quot;segoe ui&quot;,arial,freesans,sans-serif,&quot;apple color emoji&quot;,&quot;segoe ui emoji&quot;,&quot;segoe ui symbol&quot;" class=""><a href="https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#motivation" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent" target="_blank" class=""></a>Motivation</h2><ul style="padding-left:2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:&quot;helvetica neue&quot;,helvetica,&quot;segoe ui&quot;,arial,freesans,sans-serif,&quot;apple color emoji&quot;,&quot;segoe ui emoji&quot;,&quot;segoe ui symbol&quot;;font-size:16px;line-height:25.6px" class=""><li class="">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<span class="">&nbsp;</span><a href="https://en.wikipedia.org/wiki/Liskov_substitution_principle" style="color:rgb(64,120,192);text-decoration:none;background-color:transparent" target="_blank" class="">Liskov substitution principle</a>.</li><li class="">Defaulting to non-<code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">final</code><span class="">&nbsp;</span>allows the author of a class to accidentally leave the visible methods open for overrides, even if they didn't carefully consider this possibility.</li><li class="">Requiring that the author of a class mark a class as<span class="">&nbsp;</span><code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">open</code><span class="">&nbsp;</span>is akin to requiring symbols to be explicitly<span class="">&nbsp;</span><code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">public</code>: it ensures that a conscious decision is made regarding whether the ability to subclass a<span class="">&nbsp;</span><code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">class</code><span class="">&nbsp;</span>is part of the API.</li></ul><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:&quot;helvetica neue&quot;,helvetica,&quot;segoe ui&quot;,arial,freesans,sans-serif,&quot;apple color emoji&quot;,&quot;segoe ui emoji&quot;,&quot;segoe ui symbol&quot;" class=""><a href="https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#proposed-solution" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent" target="_blank" class=""></a>Proposed solution</h2><ul style="padding-left:2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:&quot;helvetica neue&quot;,helvetica,&quot;segoe ui&quot;,arial,freesans,sans-serif,&quot;apple color emoji&quot;,&quot;segoe ui emoji&quot;,&quot;segoe ui symbol&quot;;font-size:16px;line-height:25.6px" class=""><li class="">New<span class="">&nbsp;</span><code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">sealed</code><span class="">&nbsp;</span><span style="line-height:25.6px" class="">(</span><em style="line-height:25.6px" class="">actual name pending bike-shedding</em><span style="line-height:25.6px" class="">)&nbsp;</span>class modifier for classes and methods which marks them as only overridable within the module they're declared in.</li><li class=""><code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">sealed</code><span class="">&nbsp;</span>becomes the default for classes and methods.</li><li class="">New<span class="">&nbsp;</span><code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">open</code><span class="">&nbsp;</span>(<em class="">actual name pending bike-shedding</em>) class modifier to explicitly mark a class or a method as<span class="">&nbsp;</span><code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">overridable</code>.</li></ul><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:&quot;helvetica neue&quot;,helvetica,&quot;segoe ui&quot;,arial,freesans,sans-serif,&quot;apple color emoji&quot;,&quot;segoe ui emoji&quot;,&quot;segoe ui symbol&quot;" class=""><a href="https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#detailed-design" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent" target="_blank" class=""></a>Detailed design</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:&quot;helvetica neue&quot;,helvetica,&quot;segoe ui&quot;,arial,freesans,sans-serif,&quot;apple color emoji&quot;,&quot;segoe ui emoji&quot;,&quot;segoe ui symbol&quot;;font-size:16px;line-height:25.6px" class="">Code Examples:</p><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:&quot;helvetica neue&quot;,helvetica,&quot;segoe ui&quot;,arial,freesans,sans-serif,&quot;apple color emoji&quot;,&quot;segoe ui emoji&quot;,&quot;segoe ui symbol&quot;;font-size:16px;line-height:25.6px" class=""><pre style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;border-radius:3px;word-break:normal;background-color:rgb(247,247,247)" class=""><span style="color:rgb(150,152,150)" class="">/// ModuleA:</span>

<span style="color:rgb(150,152,150)" class="">/// This class is `sealed` by default.</span>
<span style="color:rgb(150,152,150)" class="">/// This is equivalent to `sealed class SealedParentClass`</span>
<span style="color:rgb(167,29,93)" class="">class</span> SealedParentClass {
    <span style="color:rgb(150,152,150)" class="">/// This method is `sealed` by default`.</span>
    <span style="color:rgb(167,29,93)" class="">func</span> <span style="color:rgb(121,93,163)" class="">foo</span>()

    <span style="color:rgb(150,152,150)" class="">/// This raises a compilation error: a method can't have a "subclassability"</span>
    <span style="color:rgb(150,152,150)" class="">/// level higher than that of its class.</span>
    open <span style="color:rgb(167,29,93)" class="">func</span> <span style="color:rgb(121,93,163)" class="">bar</span>()

    <span style="color:rgb(150,152,150)" class="">/// The behavior of `final` methods remains unchanged.</span>
    <span style="color:rgb(167,29,93)" class="">final</span> <span style="color:rgb(167,29,93)" class="">func</span> <span style="color:rgb(121,93,163)" class="">baz</span>()
}

open <span style="color:rgb(167,29,93)" class="">class</span> OpenParentClass {
    <span style="color:rgb(150,152,150)" class="">/// This method is `sealed` by default`.</span>
    <span style="color:rgb(167,29,93)" class="">func</span> <span style="color:rgb(121,93,163)" class="">foo</span>()

    <span style="color:rgb(150,152,150)" class="">/// Overridable methods in an `open` class must be explicitly marked as `open`.</span>
    open <span style="color:rgb(167,29,93)" class="">func</span> <span style="color:rgb(121,93,163)" class="">bar</span>()

    <span style="color:rgb(150,152,150)" class="">/// The behavior of a `final` method remains unchanged.</span>
    <span style="color:rgb(167,29,93)" class="">final</span> <span style="color:rgb(167,29,93)" class="">func</span> <span style="color:rgb(121,93,163)" class="">baz</span>()
}

<span style="color:rgb(150,152,150)" class="">/// The behavior of `final` classes remains unchanged.</span>
<span style="color:rgb(167,29,93)" class="">final</span> <span style="color:rgb(167,29,93)" class="">class</span> FinalClass { }</pre></div><div style="margin-bottom:16px;color:rgb(51,51,51);font-family:&quot;helvetica neue&quot;,helvetica,&quot;segoe ui&quot;,arial,freesans,sans-serif,&quot;apple color emoji&quot;,&quot;segoe ui emoji&quot;,&quot;segoe ui symbol&quot;;font-size:16px;line-height:25.6px" class=""><pre style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;margin-top:0px;margin-bottom:0px;font-stretch:normal;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;border-radius:3px;word-break:normal;background-color:rgb(247,247,247)" class=""><span style="color:rgb(150,152,150)" class="">/// ModuleB:</span>

<span style="color:rgb(167,29,93)" class="">import</span> <span style="color:rgb(0,134,179)" class="">ModuleA</span>

<span style="color:rgb(150,152,150)" class="">/// This raises a compilation error: ParentClass is effectively `final` from</span>
<span style="color:rgb(150,152,150)" class="">/// this module's point of view.</span>
<span style="color:rgb(167,29,93)" class="">class</span> SubclassA <span style="color:rgb(167,29,93)" class="">:</span> SealedParentClass { }

<span style="color:rgb(150,152,150)" class="">/// This is allowed since `OpenParentClass` has been marked explicitly `open`</span>
<span style="color:rgb(167,29,93)" class="">class</span> SubclassB <span style="color:rgb(167,29,93)" class="">:</span> OpenParentClass {
    <span style="color:rgb(150,152,150)" class="">/// This raises a compilation error: `OpenParentClass.foo` is</span>
    <span style="color:rgb(150,152,150)" class="">/// effectively `final` outside of `ModuleA`.</span>
    <span style="color:rgb(167,29,93)" class="">override</span> <span style="color:rgb(167,29,93)" class="">func</span> <span style="color:rgb(121,93,163)" class="">foo</span>() { }

    <span style="color:rgb(150,152,150)" class="">/// This is allowed since `OpenParentClass.bar` is explicitly `open`.</span>
    <span style="color:rgb(167,29,93)" class="">override</span> <span style="color:rgb(167,29,93)" class="">func</span> <span style="color:rgb(121,93,163)" class="">bar</span>() { }
}</pre></div><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:&quot;helvetica neue&quot;,helvetica,&quot;segoe ui&quot;,arial,freesans,sans-serif,&quot;apple color emoji&quot;,&quot;segoe ui emoji&quot;,&quot;segoe ui symbol&quot;" class=""><a href="https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#impact-on-existing-code" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent" target="_blank" class=""></a>Impact on existing code</h2><ul style="padding-left:2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:&quot;helvetica neue&quot;,helvetica,&quot;segoe ui&quot;,arial,freesans,sans-serif,&quot;apple color emoji&quot;,&quot;segoe ui emoji&quot;,&quot;segoe ui symbol&quot;;font-size:16px;line-height:25.6px" class=""><li class="">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<span class="">&nbsp;</span><code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">open</code>.</li></ul><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:&quot;helvetica neue&quot;,helvetica,&quot;segoe ui&quot;,arial,freesans,sans-serif,&quot;apple color emoji&quot;,&quot;segoe ui emoji&quot;,&quot;segoe ui symbol&quot;" class=""><a href="https://github.com/JaviSoto/swift-evolution/blob/a46877afb0302d2b03fa493255f5ced04ccb7f34/proposals/0000-sealed-by-default.md#alternatives-considered" style="color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1;background-color:transparent" target="_blank" class=""></a>Alternatives considered</h2><ul style="padding-left:2em;margin-top:0px;color:rgb(51,51,51);font-family:&quot;helvetica neue&quot;,helvetica,&quot;segoe ui&quot;,arial,freesans,sans-serif,&quot;apple color emoji&quot;,&quot;segoe ui emoji&quot;,&quot;segoe ui symbol&quot;;font-size:16px;line-height:25.6px;margin-bottom:0px" class=""><li class="">Defaulting to<span class="">&nbsp;</span><code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">final</code><span class="">&nbsp;</span>instead: This would be comparable to Swift defaulting to<span class="">&nbsp;</span><code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">private</code>, as opposed to<span class="">&nbsp;</span><code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">internal</code>. Just like<span class="">&nbsp;</span><code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">internal</code><span class="">&nbsp;</span>is a better trade-off,<span class="">&nbsp;</span><code style="font-family:consolas,&quot;liberation mono&quot;,menlo,courier,monospace;font-size:13.6px;padding:0.2em 0px;margin:0px;border-radius:3px;background-color:rgba(0,0,0,0.0392157)" class="">sealed</code><span class="">&nbsp;</span>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.</li></ul></div></div><div dir="ltr" class="">-- <br class=""></div><div data-smartmail="gmail_signature" class=""><div dir="ltr" class="">Javier Soto</div></div></div></blockquote></div></div><div style="word-wrap:break-word" class=""><div class=""><blockquote type="cite" class=""><div class="">
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote></div><br class=""></div></blockquote></div><div dir="ltr" class="">-- <br class=""></div><div data-smartmail="gmail_signature" class=""><div dir="ltr" class="">Javier Soto</div></div>
</div></blockquote></div><br class=""></body></html>