<html><head><style>
body {
        font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
        padding:1em;
        margin:auto;
        background:#fefefe;
}
h1, h2, h3, h4, h5, h6 {
        font-weight: bold;
}
h1 {
        color: #000000;
        font-size: 28pt;
}
h2 {
        border-bottom: 1px solid #CCCCCC;
        color: #000000;
        font-size: 24px;
}
h3 {
        font-size: 18px;
}
h4 {
        font-size: 16px;
}
h5 {
        font-size: 14px;
}
h6 {
        color: #777777;
        background-color: inherit;
        font-size: 14px;
}
hr {
        height: 0.2em;
        border: 0;
        color: #CCCCCC;
        background-color: #CCCCCC;
display: inherit;
}
p, blockquote, ul, ol, dl, li, table, pre {
        margin: 15px 0;
}
a, a:visited {
        color: #4183C4;
        background-color: inherit;
        text-decoration: none;
}
#message {
        border-radius: 6px;
        border: 1px solid #ccc;
        display:block;
        width:100%;
        height:60px;
        margin:6px 0px;
}
button, #ws {
        font-size: 12 pt;
        padding: 4px 6px;
        border-radius: 5px;
        border: 1px solid #bbb;
        background-color: #eee;
}
code, pre, #ws, #message {
        font-family: Monaco;
        font-size: 10pt;
        border-radius: 3px;
        background-color: #F8F8F8;
        color: inherit;
}
code {
        border: 1px solid #EAEAEA;
        margin: 0 2px;
        padding: 0 5px;
}
pre {
        border: 1px solid #CCCCCC;
        overflow: auto;
        padding: 4px 8px;
}
pre > code {
        border: 0;
        margin: 0;
        padding: 0;
}
#ws { background-color: #f8f8f8; }
.bloop_markdown table {
border-collapse: collapse;
font-family: Helvetica, arial, freesans, clean, sans-serif;
color: rgb(51, 51, 51);
font-size: 15px; line-height: 25px;
padding: 0; }
.bloop_markdown table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }
.bloop_markdown table tr:nth-child(2n) {
background-color: #f8f8f8; }
.bloop_markdown table tr th {
font-weight: bold;
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
.bloop_markdown table tr td {
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
.bloop_markdown table tr th :first-child, table tr td :first-child {
margin-top: 0; }
.bloop_markdown table tr th :last-child, table tr td :last-child {
margin-bottom: 0; }
.bloop_markdown blockquote{
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777; }
blockquote > :first-child {
margin-top: 0; }
blockquote > :last-child {
margin-bottom: 0; }
code, pre, #ws, #message {
word-break: normal;
word-wrap: normal;
}
hr {
display: inherit;
}
.bloop_markdown :first-child {
-webkit-margin-before: 0;
}
code, pre, #ws, #message {
font-family: Menlo, Consolas, Liberation Mono, Courier, monospace;
}
.send { color:#77bb77; }
.server { color:#7799bb; }
.error { color:#AA0000; }</style></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="bloop_markdown"><p>I’ll try again to make it a little bit more simpler.</p>
<p>Assume we want to implement my feature to support <code>document["string_literal", stringInstance, integerInstance, 42]</code> where the first parameter type is always a String but the types follow afterward are either a String or an Int (literals should be supported too).</p>
<pre><code class="swift">// Module A
// Today only `public` is allowed on protocols.
// `public protocol` means almost the same as `open class`.
// One is 'you can conform to it outside module A'
// the other is 'you can subclass to it outside module A'
// First idea
public SubscriptParameterType {}
extension Int : SubscriptParameterType {}
extension String : SubscriptParameterType {}
extension Document {
public subscript(firstKey: String, parameters: SubscriptParameterType...) -> Value? {
// CAST any instance of `SubscriptParameterType` to Int or String
}
}
// Module B
extension NSObject : SubscriptParameterType {}
// Lets try breaking module A
document["test", NSObject()] // Runtime error, because something unexpected happened in module A
// The reason is we let the client (module B) the ability to conform to our type without any requirements.
// To solve that issue we need TODAY a requirement on our protocol `SubscriptParameterType` (see my previous post)
// I already mentioned that the workaround creates unnecessary boilerplate in my library.
// We could clean everything up iff we had consistent `public` vs. `open` behavior. I will use `pulic-but-not-open` and `open` annotation now.
pulic-but-not-open SubscriptParameterType {}
extension Int : SubscriptParameterType {}
extension String : SubscriptParameterType {}
// Module B
extension NSObject : SubscriptParameterType {} // Error, `SubscriptParameterType` is closed and cannot be conformed to outside module A!!
</code></pre>
<p>This feature is ridiculously powerful. </p>
<p></p></div><div class="bloop_original_html"><style>body{font-family:Helvetica,Arial;font-size:13px}</style><div id="bloop_customfont" style="font-family:Helvetica,Arial;font-size:13px; color: rgba(0,0,0,1.0); margin: 0px; line-height: auto;"><br></div> <br> <div id="bloop_sign_1487181595411425024" class="bloop_sign"><div style="font-family:helvetica,arial;font-size:13px">-- <br>Adrian Zubarev<br>Sent with Airmail</div></div> <br><p class="airmail_on">Am 15. Februar 2017 um 18:57:50, Rien via swift-evolution (<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>) schrieb:</p> <blockquote type="cite" class="clean_bq"><span><div><div></div><div><br>> On 15 Feb 2017, at 17:45, Matthew Johnson <matthew@anandabits.com> wrote:<br>> <br>> <br>>> On Feb 15, 2017, at 10:35 AM, Rien <Rien@Balancingrock.nl> wrote:<br>>> <br>>>> <br>>>> On 15 Feb 2017, at 17:02, Matthew Johnson <matthew@anandabits.com> wrote:<br>>>> <br>>>>> <br>>>>> On Feb 15, 2017, at 9:59 AM, Rien <Rien@Balancingrock.nl> wrote:<br>>>>> <br>>>>>> <br>>>>>> On 15 Feb 2017, at 16:45, Matthew Johnson <matthew@anandabits.com> wrote:<br>>>>>> <br>>>>>>> <br>>>>>>> On Feb 15, 2017, at 9:35 AM, Rien <Rien@Balancingrock.nl> wrote:<br>>>>>>> <br>>>>>>> <br>>>>>>>> On 15 Feb 2017, at 16:11, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:<br>>>>>>>> <br>>>>>>>> <br>>>>>>>>> On Feb 15, 2017, at 5:59 AM, Jeremy Pereira via swift-evolution <swift-evolution@swift.org> wrote:<br>>>>>>>>> <br>>>>>>>>> <br>>>>>>>>>> On 15 Feb 2017, at 11:11, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:<br>>>>>>>>>> <br>>>>>>>>>> <br>>>>>>>>>> Our philosophy in general, however, is to default to the behavior which preserves the most flexibility for the library designer.<br>>>>>>>>> <br>>>>>>>>> Actually, I thought the philosophy was to preserver type safety. When did that change?<br>>>>>>>>> <br>>>>>>>>> Also, when was the library designer prioritised ahead of the application developer?<br>>>>>>>>> <br>>>>>>>>> <br>>>>>>>>>> Both open and non-open classes are common, but we chose to give non-open classes the `public` keyword because that's the flexibility-preserving option.<br>>>>>>>>> <br>>>>>>>>> No it isn’t, it’s the flexibility restricting option. The consumer of an open class can subclass it. The consumer of a public class cannot subclass it. How is the second more flexible than the first?<br>>>>>>>> <br>>>>>>>> It reduces complexity for the library author by allowing them to opt-out of the complexity involved in supporting unknown, user-defined subclasses. It is important to allow libraries to have this flexibility. They are free to declare a class `open` if they want to allow subclassing. It’s even possibly for a library to declare all classes `open` if it wishes to do so. But *requiring* that would reduce the design space libraries are allowed to explore and / or introduce fragility by moving the subclass restriction to a comment.<br>>>>>>>> <br>>>>>>> <br>>>>>>> Why would a library author want to prohibit subclasses?<br>>>>>>> A library user can always wrap the class and subclass the wrapper.<br>>>>>> <br>>>>>> This is composition, not inheritance. The most important difference is that a wrapper cannot override methods, it can only wrap and / or forward them. This means that when the superclass calls a method on `self` that method *always* invokes its version of that method rather than a subclass override. This is a very important difference.<br>>>>>> <br>>>>> <br>>>>> Agreed, however that does not answer the question why would a library developer want to disallow subclassing?<br>>>>> I do not see a use case for that. I.e. a feature that cannot be implemented without it. (without “open”)<br>>>> <br>>>> The feature it enables is more robust libraries and the ability for library authors to better reason about their code. You may not find this benefit enough to be worth a language feature, but many of us do.<br>>> <br>>> You start of with a claim “more robust libraries”.<br>>> I would really like to know the “how” of that. How does it make a library more robust?<br>>> <br>>> I do write libraries myself, and if there is something I am missing, I very much would like to know.<br>> <br>> This topic was well explored during the discussion and review of the proposal that introduced `open`. If you would really like to know I suggest you take some time to read through that discussion.<br><br>I did (proposal 117), while it was mentioned a few times “if not carefully designed for subclassing” there is no example on how open vs public prevents anything.<br><br>Mind you, it could be argued that the default of “internal” instead of “open” can prevent something (though I still don’t know what). But adding “open” does imo not prevent anything.<br><br>Besides: a monkey with a tool is still a monkey.<br><br>I.e. devs that now start using “open” vs “public” because it all is a hassle to figure out what should be “internal”, “public” or “open” will still make the same errors (which ones?) as before.<br>Thus while there is a lot of bad code around (partly mine!) that does not disappear because the default is not “not subclassable”.<br><br>(PS: I am still trying to get my head around Adrian’s example)<br><br>Regards,<br>Rien.<br><br>> <br>>> <br>>> Regards,<br>>> Rien.<br>>> <br>>>> <br>>>>> <br>>>>> Rien.<br>>>>> <br>>>>>>> <br>>>>>>> There are cases where subclassing does not make sense. And thus preventing subclasses adds information for those users that don’t RTFM. But that imo is not worth the impact extra complexity places on all other users.<br>>>>>>> <br>>>>>>> Rien.<br>>>>>>> <br>>>>>>>>> <br>>>>>>>>> <br>>>>>>>>> _______________________________________________<br>>>>>>>>> swift-evolution mailing list<br>>>>>>>>> swift-evolution@swift.org<br>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution<br>>>>>>>> <br>>>>>>>> _______________________________________________<br>>>>>>>> swift-evolution mailing list<br>>>>>>>> swift-evolution@swift.org<br>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution<br>> <br><br>_______________________________________________<br>swift-evolution mailing list<br>swift-evolution@swift.org<br>https://lists.swift.org/mailman/listinfo/swift-evolution<br></div></div></span></blockquote></div><div class="bloop_markdown"><p></p></div></body></html>