<div dir="ltr"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex">However, once we&#39;ve got non-open public classes — and as I understand it, you still support those — that complexity already exists.  You&#39;re not really eliminating anything by preventing this from being applied to methods.</blockquote><div><div class="gmail_extra"><br></div><div class="gmail_extra">We may not need to prevent public members from being declared non-open, however I think that by *default* public members should be open.</div><div class="gmail_extra"><br></div><div class="gmail_extra">Notably, one of the primary reasons for opening a class is to allow its members to be overridden outside the module. In the by-all-accounts-rare scenario that one or more public members of an open class should be non-open, then they can be marked as such (or just use Károly’s trick with `final` forwarding to `internal`).</div><div class="gmail_extra"><br></div><div class="gmail_extra">I am reminded of the `atomic` / `nonatomic` situation in Objective-C. Yes, `atomic` is generally safer, but almost every property in almost every class is declared `nonatomic`. It was a mistake to set `atomic` as the default, which caused a profusion of noise in property declarations.</div><div class="gmail_extra"><br></div><div class="gmail_extra">If we were to make public members default to non-open, the result would be similar: an extra keyword (`open`) appearing in almost every public declaration in almost every open class.</div><div class="gmail_extra"><br></div><div class="gmail_extra">The 80-20 rule may be applicable here: if even 1 out of 5 public members ought to be non-open, then perhaps a consistency argument could be made. But with non-open members being an essentially negligible fraction, I do not see anything gained by <i>de facto</i> changing the spelling of `public` to `public open` for members of open classes.</div><div class="gmail_extra"><br></div><div class="gmail_extra">In sum, the default for public members should probably be `open`.</div><div class="gmail_extra"><br></div><div class="gmail_extra">(I am fully on board with public *classes* defaulting to non-open.)</div><div class="gmail_extra"><br></div><div class="gmail_extra">Nevin</div><div class="gmail_extra"><br></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jul 20, 2016 at 1:34 PM, John McCall via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><span class="">&gt; On Jul 20, 2016, at 10:13 AM, Károly Lőrentey &lt;<a href="mailto:karoly@lorentey.hu">karoly@lorentey.hu</a>&gt; wrote:<br>
&gt;&gt; On 2016-07-18, at 19:05, John McCall via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:<br>
&gt;&gt; The basic effect of Károly&#39;s counter-proposal is that every public member of an open class has to be marked either &quot;open&quot; or &quot;final&quot;.  That&#39;s boilerplate.<br>
&gt;<br>
&gt; My primary point was that there is no need for a middle ground between &quot;final&quot; and &quot;open&quot; members.<br>
&gt;<br>
&gt; I want to push my primary point a little more, so let’s forget my secondary suggestion to have no default, and let’s set an implicit choice.<br>
&gt;<br>
&gt; I&#39;d still argue for having no middle ground. “final” seems to be a good default; its effect matches the proposal.<br>
&gt;<br>
&gt;&gt; I think you and Károly are evaluating the addition of non-open methods as if they were being added primarily to increase expressive capabilities.  They do marginally increase expressiveness, but I agree that it&#39;s not a common situation to explicitly want.  However, neither are non-open classes.<br>
&gt;<br>
&gt; It&#39;s more of an Occam&#39;s razor thing. The proposal prevents people from unintentionally exposing a wider API area than they intended. I agree with this wholeheartedly. I just don&#39;t believe that we need to add a brand new access level for members to achieve this goal.<br>
&gt;<br>
&gt; Having an implicit &quot;sealed&quot; class level is a much easier sell for me, because it is sometimes desirable to expose a sealed class hierarchy, but Swift doesn&#39;t currently support it well -- AFAICT not as an intentional choice, but rather as an unfortunate side-effect of the initializer rules. You could&#39;ve simply chosen to propose making &quot;final&quot; the default for public classes. Kotlin&#39;s troubles mostly wouldn&#39;t apply as long as internal classes would remain open, so I&#39;d have supported that too. But rather than this, the proposal is built on top a nice solution to the sealed class problem. Solving it is obviously a good idea, and it is closely related to the goal of the proposal.<br>
&gt;<br>
&gt; There is no such language problem in Swift 2 with sealed methods: an internal open member is sealed by virtue of not being externally visible. It’s straightforward to add a public final trampoline in the rare case when a sealed member should also be made externally callable. I believe the proposal works perfectly well without adding a language feature for this uncommon usecase.<br>
&gt;<br>
&gt;&gt; The goal here is not to create new expressive power, it&#39;s to establish a comprehensible intermediate position that&#39;s acceptable as a default so that publicizing an API doesn&#39;t require so much annotation and bookkeeping.  Otherwise, programmers are forced to immediately decide between over-promising (by making the method publicly overridable) or breaking their own code (if they have internal overrides).<br>
&gt;<br>
&gt; But making API public should never be done in a hurry. It includes making the API presentable, which involves some amount of refactoring. Granted, if an API has internally overridden methods that the author wants to make public but sealed, then they&#39;d need to refactor these methods. But given how rare this is, and how easy it is to implement the trampoline pattern, is such a trivial refactoring step really too much to ask? (There are a number of much more complicated refactorings involved in making an API public; e.g., it is often the case that a method I want to make public has a parameter or return value with a type that I wish to keep internal.)<br>
<br>
</span>I agree that having the concept of &quot;visible publicly but only arbitrary modifiable internally&quot; adds complexity to the language.  However, once we&#39;ve got non-open public classes — and as I understand it, you still support those — that complexity already exists.  You&#39;re not really eliminating anything by preventing this from being applied to methods.<br>
<br>
Also, we&#39;re going to be proposing a lot of new things for library-resilience over the next six months or so that will add appreciable but unavoidable complexity to the language around module boundaries.  Module boundaries have a lot of special significance in the language design because Swift takes the stable binary interface problem much more seriously than, I think, almost any other language can claim to.<br>
<span class=""><br>
&gt; I believe that apart from this one little wrinkle, the behavior that SE-0117 proposes can be fully implemented by allowing just &quot;final&quot;, &quot;open&quot; and &quot;dynamic&quot; members, with &quot;final&quot; being the default for public members of open classes, and &quot;open&quot; being the default for all other members (including non-open classes).<br>
&gt;<br>
&gt; Is smoothing out that wrinkle worth introducing a whole new default level of member overridability? I think this is worth some more discussion.<br>
&gt;<br>
&gt; Note that if we end up with &quot;final” members by default and it turns out to be the wrong choice, changing the default to sealed would not be a source-breaking change.<br>
&gt;<br>
&gt;&gt; Furthermore, I don&#39;t agree that non-open methods add significant new complexity.  For clients of a library, a non-open method is final; there are no semantically-detectable differences (ignoring covariant overrides).  Within a library, non-open methods remove the need for some unnecessary bookkeeping.  And just on a conceptual level, the analogy to class behavior is quite simple.<br>
&gt;<br>
&gt; This reminds me: Whether or not we allow the sealed level on methods, I suggest we provide a contextual keyword to (optionally) spell it. A &quot;sealed&quot; keyword is the obvious choice. This would encourage people to use common terminology, and makes it easier to use search engines to find an explanation of the concept. Autogenerated API summaries should add the &quot;sealed&quot; keyword.<br>
<br>
</span>Yes, we should probably add some way to spell it.  &quot;sealed&quot; does not feel like a natural opposite to &quot;open&quot;, however, and I think we&#39;re quite taken with &quot;open&quot;.  I would suggest &quot;nonopen&quot; or &quot;closed&quot;.<br>
<br>
John.<br>
<div class=""><div class="h5"><br>
&gt;<br>
&gt; We never have to spell &quot;internal&quot;, but I think it is still very useful that it exists.<br>
&gt;<br>
&gt; --<br>
&gt; Károly<br>
&gt; @lorentey<br>
&gt;<br>
<br>
_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</div></div></blockquote></div><br></div></div></div>