<div dir="ltr">On Wed, Jun 29, 2016 at 12:20 PM, Jordan Rose <span dir="ltr">&lt;<a href="mailto:jordan_rose@apple.com" target="_blank">jordan_rose@apple.com</a>&gt;</span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><br><div><div><div class="h5"><blockquote type="cite"><div>On Jun 29, 2016, at 09:59, Xiaodi Wu &lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>&gt; wrote:</div><br><div><div dir="ltr">On Wed, Jun 29, 2016 at 11:31 AM, Jordan Rose <span dir="ltr">&lt;<a href="mailto:jordan_rose@apple.com" target="_blank">jordan_rose@apple.com</a>&gt;</span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><br><div><blockquote type="cite"><div>On Jun 29, 2016, at 08:49, Xiaodi Wu &lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>&gt; wrote:</div><br><div><div dir="ltr">On Tue, Jun 28, 2016 at 9:06 PM, Jordan Rose 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><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><span><br><div><blockquote type="cite"><div>On Jun 28, 2016, at 19:03, Matthew Judge &lt;<a href="mailto:matthew.judge@gmail.com" target="_blank">matthew.judge@gmail.com</a>&gt; wrote:</div><br><div><div dir="auto"><div></div><div>Comments inline.</div><div><br>On Jun 28, 2016, at 04:14, David Hart via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:<br><br></div><blockquote type="cite"><div>Hello everybody,<div><br></div><div>I tried using the access rules defined in SE-0025 in some code of mine to see what effect it would have. I came out of the experiment more disappointed than I thought. Here are several reasons:</div><div><br></div><div>1) The new rules make `private` more prominent compared to `fileprivate` (the latter has a somewhat worse name). But at the same time, the Swift community has developed a style of coding where a type is defined through a set of extensions. To hide members from other types, but have access to them inside the type extensions, we have often used `private` and placed the type and its extensions in the same file. Because `private` is scoped, we are forced into using `fileprivate` pervasively (which is uglier), using `internal` instead (which is less safe) or moving the extension code into the type&#39;s scope (which is against the way Swift code is being written today). All of these options look worse to be than before SE-0025.</div></div></blockquote><div><br></div>If I understand SE-0025 (even with the amendment) you can still spell the access modifier to types as &#39;private&#39; and get the same characteristics as the pre-SE-0025 meaning or private, so I&#39;m not sure I understand the concern here. However (continued below)<br><blockquote type="cite"><div><div><br></div><div>2) The new amended rules look complicated to me. I think they have the risk of being confusing in practice, but we’ll have to see.</div><div><br></div></div></blockquote><div><br></div><div>I definitely agree that the amended rules look complicated. It seems to me that the amended set of rules is favoring simplifying the implementation over simplifying the mental model.</div><div><br></div><div>My impression of what SE-0025 decided was that &#39;private&#39; meant private to the enclosing scope. If the access modifying &#39;private&#39; was applied to a type at the file scope, then it was synonymous with fileprivate and the default access of members of that type should be fileprivate.</div><div><br></div><div>If a inner type was declared private, than the default access of members of that inner type should be private to the Outer type, not fileprivate. There is currently no way of expressing this access explicitly, but it does not seem like an especially useful thing to need to spell.</div><div><br></div><div>Said in code, my impression of SE-0025 is that </div><div><br></div><div>private class Outer { // exactly equivalent to fileprivate</div><div>    var myVar = 0 // default: fileprivate</div><div>    private class Inner { // private to Outer</div><div>        var hiddenVar = 0 // default: private to Outer</div><div>        private var reallyHiddenVar = 0 // default private to Inner</div><div>    }</div><div>}</div></div></div></blockquote><br></div></span><div>This is definitely one of the considered alternatives. Both Brent and I didn’t like the idea of an access level that you couldn’t actually spell, and even if we got past that, we’d still need a way to refer to it in documentation and diagnostics. I would count that as a larger change than just allowing ‘fileprivate’ in places that previously would have been called redundant.</div></div></blockquote><div><br></div><div>I&#39;m late to the party here, but I share the feeling that perhaps the amendment introduces a complicated mental model. But a lightbulb went off reading the amendment, specifically this parenthetical statement:</div><div><br></div><div>&quot;(The members [defaulting to fileprivate inside a private type] still cannot be accessed outside the enclosing lexical scope because the type itself is still private, i.e. outside code will never encounter a value of that type.)&quot;</div><div><br></div><div>Given that this is the case, wouldn&#39;t the same problem be entirely obviated by the following change to the formal rules:</div><div>The default level of access control within any type (public, internal, fileprivate, or private) is `internal`.<br></div><div><br></div><div>In the case of fileprivate or private types, the `internal` members still cannot be accessed where the containing type cannot be accessed.</div></div></div></div></div></blockquote><br></div><div>That does seem simpler at first, but it doesn’t remove any of the later, more complicated rules about <i>minimum</i> access, and when you can use a less accessible type in a (formally but not in practice) more-accessible declaration.</div></div></blockquote><div><br></div><div>Your second rule as written is straight-up ungrammatical, so I can&#39;t say if it makes any sense or becomes any more or less complicated (&quot;a member...may have `private` type&quot;--huh?).<br></div></div></div></div></div></blockquote><div><br></div></div></div><div>It’s…compiler-grammar? We say something “has pointer type” fairly often within the compiler group. I’ll change it.</div><div><br></div><div>“A method, initializer, subscript, property, or typealias with `fileprivate` access may have a type that references `private` declarations if (1) the declaration with `fileprivate` access is a member of a private type, and (2) all referenced `private` declarations are defined within an enclosing lexical scope. That is, it is legal for a `fileprivate` member within a `private` type to have a type that is formally `private` if it would be legal for a `private` declaration in the parent scope to have that type.”</div><div><br></div><div>Is this clear, or still senseless?</div></div></div></blockquote><div><br></div><div>That&#39;s very clear now.</div><div><br></div><div>Independent of the issue of the written text, though, the idea you are expressing is very complicated and a special case for a generalizable principle. That is, if you loosen the requirement so that a method, etc., can have an access level formally broader than that of its containing type (in your example below, `Inner`), it should still be permissible for that method to make use of a type with more restrictive access if that restrictive access is at least as broad as that of the containing type.<br></div><div> </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"><div><div><br></div><div>This rule is intended to allow this case:</div><div><br></div></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><div>struct Outer {</div><div>  private typealias Value = Int</div><div>  private struct Inner {</div><div>    /*fileprivate*/ var value: Value</div><div>  }</div><div>}</div></div></blockquote><div><br></div>while disallowing this case:<div><br></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div>struct Outer {</div><div>  private struct Inner {</div><div>    private typealias Value = Int</div><div>    fileprivate var value: Value = 0</div><div>  }</div><div>}</div></blockquote><div><br></div>Do you think that should appear in the proposal text?<br></div></blockquote><div><br></div><div>I think that would help.</div><div> </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"><div><div><span class=""><div><br></div><br><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>The rule about minimum access is needlessly complicated: `private` can never satisfy a protocol requirement or be used for a required initializer because of the very fact that it is private. We needn&#39;t say that `fileprivate` is the minimum access required since there&#39;s nothing about `fileprivate` that makes it the minimum. Thought experiment: if another access level were to be introduced between `private` and `fileprivate`, that could become the minimum access required. However, no matter what, it is inherent to the SE-0025 definition of `private` that it can never satisfy a requirement.</div></div></div></div></div></blockquote><div><br></div></span><div>I admit that I don’t think most people understand what the rules are for minimum access to satisfy a requirement: the minimum of the type’s access and the protocol’s access. But maybe it’s good enough to say “A private member may never satisfy a protocol requirement. Required initializers may not be private.” and not give further justification; the previous changes already allow that. (I already ducked out of justification by saying “to satisfy the spirit of existing requirements”, so this wouldn’t really be any worse.)</div><span class=""><div><br></div><br><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>The rule about members inside extensions with access modifiers is consistent with existing rules and doesn&#39;t need to be called out. That said, does a `private extension` make sense at all?</div></div></div></div></div></blockquote><div><br></div></span><div>I was inclined to write it explicitly after Adrian Z’s proposal to change the behavior of extensions, which implied to me that the current behavior was non-obvious. Since extensions just set the default access level, I could see <i>someone</i> doing this to enforce that access to all of their non-helper API was called out explicitly. I’m not a fan, but it doesn’t seem to hurt anything.</div></div></div></div></blockquote><div><br></div><div>It raises a question. Is `foo` inside `private extension { func foo... }` supposed to be exactly the same as that inside `extension { private func foo... }` (i.e. not visible outside the extension)? That seems useless and counterintuitive. However, if not, then `private extension { func foo... }` is equivalent to `fileprivate extension { func foo... }`, which is both confusing and redundant.</div><div><br></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"><div><div><span class=""><div><br></div><br><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div>Once those are in place, it seems better to use fileprivate, as the next level up, so that we can still warn about mistaken uses of ‘internal’, and so that we don’t have to special-case code later on in the pipeline that uses visibility to optimize.</div></div></blockquote><div><br></div><div>Mistaken explicit use of `internal` can still be warned on. In your proposal, `fileprivate` inside `private` still leaves room for optimization that would require special-casing, no? In my proposed formulation, `internal` simply takes on the practical meaning of &quot;as visible to the module as can be given what it&#39;s contained in&quot;, which seems like a principled take that could be optimized without regarding it as &quot;special-casing”.</div></div></div></div></div></blockquote><div><br></div></span><div>I don’t think there are any cases of ‘fileprivate&#39; that can meaningfully be “optimized” down to ‘private’. Just because no one’s using something outside of the type <i>now</i> doesn’t mean it isn’t used at all. Maybe it’s being used on the other side of a #if branch.</div></div></div></div></blockquote><div><br></div><div>Sorry, that&#39;s not what I meant. And since I don&#39;t have the best words, it may take me a while to express my point.</div><div> </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"><div><div><span class=""><div><br></div><br><blockquote type="cite"><div><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div style="word-wrap:break-word"><div><br></div><div>(Alternately, I don’t think that’s the part of the mental model people are having trouble with.)</div></div></blockquote><div><br></div><div>Maybe it&#39;s just me, but that&#39;s the first part of the mental model that&#39;s exploding my mind. </div></div></div></div></div></blockquote><br></span></div><div>Hm. I really didn’t expect this—to me, it’s just “fileprivate is allowed inside private types” and then “fix all the fallout so that the compiler only shouts at you when necessary”. Can you say what the model change is to you?</div></div></div></blockquote><div><br></div><div>With respect to this particular rule, it&#39;s already been pointed out that things are already complicated (public types have default internal members, but internal types have default internal members and fileprivate types have default fileprivate members). Granted, there is a very good rationale for the behavior. However, add yet another subrule and you may has well just have a table, because a general rule that applies to two things with two different exceptions for two other things is essentially no general rule at all. Since the point you&#39;re making is that we have to relax the rules about access levels nested inside types anyway, the most consistent rule I can think of is &quot;the default access level is always internal&quot;. And I think it would actually be workable.</div><div><br></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"><div>Thanks for all the feedback.</div><span class="HOEnZb"><font color="#888888"><div>Jordan</div></font></span></div></blockquote></div><br></div></div>