<div dir="ltr">+1 to Karl&#39;s suggestion<div><br></div><div>I&#39;ve come around to the idea of not allowing subclassing by default (well, 50/50) because I rarely see final used in swift code (read: it&#39;s underused). However, I think the special casing of 3rd party libraries is weird.</div><div><br></div><div>Let&#39;s assume this is true: &quot;It&#39;s really bad for developers to subclass things which weren&#39;t intended to be subclassed by the developer who wrote the class.&quot;</div><div><br></div><div>Given this, we want to turn off subclassability by default (reasonable). So why is it ok for internal classes to incorrectly subclass things? The main argument against this seems like it&#39;s hard for swift beginners to learn this rule (but somehow, this proposal isn&#39;t?). Or that public APIs are &#39;more important&#39; (disagree with this generalization. it totally depends on the library/app. And even if they are more important, if it&#39;s better, then it&#39;s better for everything). Am I missing other arguments for why this would be bad for internal classes?</div><div><br></div><div><br></div><div>One other note:</div><div><br></div><div><i>From and API perspective, </i>if the developer does everything right and thinks about subclassing, there is no difference between this proposal and what we have today. As in, the developer correctly decides to add final/open (note: I know theres a different in the module itself, but from an API perspective they are the same).</div><div><br></div><div>This proposal only matter when a developer &quot;makes a mistake&quot;. It only applies to developers who forget to take subclassing into consideration.</div><div><br></div><div>I&#39;ve learned that you shouldn&#39;t optimize for bad developers. It seems like adding complexity to the language and a new keyword just so when developers make a mistake, it&#39;s not as bad seems strange to me. I think languages in general should optimize for good code, not bad.</div><div><br><div class="gmail_quote"><div dir="ltr">On Wed, Jul 20, 2016 at 4:53 PM ilya via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">&gt;  limiting “open” to public classes only lets you be sloppy inside your own module.<div><br></div></div><div dir="ltr"><div>I don&#39;t find that idea bad actually.</div><div><br></div><div>In the similar vein one can say &quot;it&#39;s ok to be sloppy with local variable names, it&#39;s not ok to be sloppy with instance variable names&quot;.</div><div><br></div><div>Again, tradeoffs. You can require that things are perfect, so that all methods are thoughtfully annotated, and all variables have wonderful self-descriptive names, but you&#39;ll get most bang for the buck by requiring that for the interface (public classes / instance variables) rather than for the implementation (non-public classes / local variables).</div><div><br></div><div><br></div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Jul 21, 2016 at 12:26 AM, Karl 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:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span><br>
&gt; On 20 Jul 2016, at 11:07, Brent Royal-Gordon &lt;<a href="mailto:brent@architechies.com" target="_blank">brent@architechies.com</a>&gt; wrote:<br>
&gt;<br>
&gt;&gt; On Jul 19, 2016, at 6:14 PM, Karl &lt;<a href="mailto:razielim@gmail.com" target="_blank">razielim@gmail.com</a>&gt; wrote:<br>
&gt;&gt;<br>
&gt;&gt; That is to say, we basically introduce “open&quot; as an inverted “final”, and make all classes non-open by default. That is analogous to enabling whole-module-optimisation by default, in my opinion. The cost of an extra four-letter word isn’t that great, but the benefits to readability and reasonability all-around make it worthwhile.<br>
&gt;<br>
&gt; Okay, but this ignores an important difference between sealed and final.<br>
&gt;<br>
&gt; Sealed is *non-committal*. It makes no promises to wider scopes about whether there are other subclasses/overrides; it merely states that code outside the module may not subclass/override. `final`, on the other hand, is an *affirmative* statement: there are no subclasses/overrides and there never will be. Code outside the module is permitted to rely on that fact—for instance, it can generate static calls and conflate dynamic Self with static Self in conformances.<br>
&gt;<br>
&gt; But this distinction only really makes sense at the `public` boundary, because that&#39;s where the compiler—and even the developer—faces an impenetrable encapsulation barrier. If you want to require `open` even on non-public declarations, you thus need to choose one of these designs:<br>
&gt;<br>
&gt;       1. `final` is still available, but only on public APIs.<br>
&gt;<br>
&gt;       2. All non-public classes have to be explicitly declared either `open` or `final`.<br>
&gt;<br>
&gt;       3. Sealed has some sort of complex, scope-specific design (for instance, an `internal` class can be subclassed in `fileprivate` but not in `internal` scope).<br>
&gt;<br>
&gt; Of these three, I think that #2 is overly bureaucratic and #3 is overly complicated, so only #1 is a viable option. And then we&#39;re just choosing whether we have internal subclassing by default and an odd public-only `open` keyword, or no internal subclassing by default and an odd public-only `final` keyword. No viable option avoids some kind of asymmetry at the `public` boundary.<br>
&gt;<br>
&gt; Open-by-default with a `final` keyword is the traditional design. It is simpler for people learning to program and more familiar for people new to Swift. It is more convenient. And you just don&#39;t need the same rigorous, formal definition of semantics in internal scope, where you can alter a problematic invariant rather than having to live with it.<br>
&gt;<br>
&gt; All that said, there most likely *is* value in declaring, even internally, which classes are meant to be subclassed and which members are meant to be overridden. Perhaps what we ought to do is permit `open` even on non-public APIs, but not enforce it (or rather, leave enforcement to linters). That would allow people and teams to explicitly document internal overriding behavior if they want to, without burdening the teams that don&#39;t want to go to the effort.<br>
&gt;<br>
&gt; --<br>
&gt; Brent Royal-Gordon<br>
&gt; Architechies<br>
&gt;<br>
<br>
<br>
</span>This is exactly what I&#39;m talking about - this is actually a very simple discussion. Throwing around words like “non-committal” and “affirmative” and speaking abstractly doesn’t disguise the brunt of what you’re saying: limiting “open” to public classes only lets you be sloppy inside your own module. That’s the only reason to make it like that. If I were describing the concept of “sloppiness” while trying my hardest not to use the word itself, I would probably say pretty much what you just wrote - wanting to remain non-committal, avoid definite, affirmative statements, etc.<br>
<br>
If we think it is important for people who write classes to locally reason about their code, it’s important full stop. The conflation between if it’s publicly accessible and whether or not is a staggeringly massive regression in read&amp;reason-ability, no matter how matter how you want to phrase it. It’s a general problem which deserves a general solution - not some ‘non-committal’ proposal which can&#39;t even commit to the problem it is trying to help with.<br>
<br>
If you’ve ever had to deal with complex base classes, consisting of a mixture of internal (and possibly internally subclassed) members and public ones, you would know that annotating which members are to be used by what (and knowing that it’s enforced by the compiler) would be a massive improvement to our language syntax. Sometimes you didn’t write all the code you have to work with, so it’s handy to have code which annotates this stuff.<br>
<br>
<br>
Karl<br>
<div><div><br>
<br>
<br>
_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">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>
_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">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>
</blockquote></div></div></div>