<div dir="ltr">Code organization of having most methods in extensions would not work for extensions that need access to internal state marked with "scoped". For this specific use case, one class per file + "private" works perfectly. This code organization makes sense for very large classes but not for smaller and related classes.<div><br></div><div>That said, I think that even in this case, "scoped" would help with hiding helper methods that are necessary to implement protocols but are useless in other places in the same file.</div><div><br></div><div>I do think that the name "private" is an unfortunate choice because it means something else in other mainstream languages, but the access level that it provides is very useful and a much better alternative than "friend" in C++. However, we still need "scoped" (private in C++) to declare and enforce encapsulation at the scope (class or extension) level.</div><div><br><div class="gmail_quote"><div dir="ltr">On Sat, Feb 27, 2016 at 10:27 AM plx via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<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><blockquote type="cite"><div><div style="word-wrap:break-word"><ul style="padding:0px 0px 0px 2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)"><li>What is your evaluation of the proposal?</li></ul></div></div></blockquote></div></div><div style="word-wrap:break-word"><div><div>Short form: the problem addressed is very real and IMHO very significant; the proposed solution is *useful* but on reflection seems to illustrate this isn’t a problem that can be *entirely* addressed just by adding another scope (or scope(s)). I think I agree with what I think Drew has been saying that the visibility model itself may be not quite ideal (it isn’t broken or anything). </div><div><br></div><div>I’m also a little unsure how useful `local` will be in the context of the rest of the language at this time; it seems like to really come into its own we’d also want e.g. to be able to split up the definition of a type across multiple extensions within the same module.</div><div><br></div><div>Longer form: within Swift’s existing access-control approach, if you want to keep things private—as opposed to merely internal—it’s easy to wind up with numerous closely-related types, all living in the same file. The only sensible visibility for most of the aspects of most of the types is `private`, but because these are all living in the same file we don’t actually get any effective "cross-type” access-protection within that file.</div><div><br></div><div>So e.g. for a custom type implementing `CollectionType`, you can have the type itself, an associated index type, and perhaps also an associated generator type; if instead of “is-a `CollectionType`” you instead opt for “has-multiple `CollectionType` views”, then you can wind up with the base type + 2-3 closely-related types per such view (the collection type, its index, and perhaps also the generator).</div><div><br></div><div>The standard-library `String` is an example, where it’s not itself a collection but has 4 “views”, each of which defines an index, and one of which also adds a custom generator.</div><div><br></div><div>I don’t have a short example I can share, but I can describe one: at one point I wrote an “accelerated 2D point array”, which was effectively an array of `CGPoint`, but in struct-of-arrays style (e.g. separate arrays of `x` and `y` coordinates). The tricky part is it had a delicate internal state, since the actual storage looked like this (many details elided here) :</div><div><br></div><div>@implementation PointArray {</div><div> float *_bufferA;</div><div> float *_bufferB;</div><div> float *_bufferC;</div><div>}</div><div><br></div><div>@property(nonatomic, assign) PointArrayState state;</div><div><br></div><div>@end</div><div><br></div><div>…wherein *which* buffer was for `x` or `y` varied over time (and was tracked via that `state` field). The reason for this design is many of the array-level operations were implemented using functions from Accelerate, which in turn often benefit from being done “out-of-place” (and thus e.g. to translate each point by dx,dy, if you started out with `bufferA` having the x-coordinates and `bufferB` having the y-coordinates, you might wind up with `bufferC` holding the updated x-coordinates and `bufferA` holding the updated y-coordinates, along with `state` updated to reflect that updated arrangement).</div><div><br></div><div>This is code that would arguably benefit from being migrated to Swift at some point. As it is in Objective-C, it’s implemented as part of a larger family of classes, and it’s easy to tightly control visibility: there’s public headers, there’s private headers imported by subclasses, and there’s methods defined in .m files that are difficult to call accidentally from anywhere else. </div><div><br></div><div>In Swift the design would change a bit — a lot of methods that in Objective-C are effectively “sort if necessary, then call this block on each point” would get migrated to “view structs” that implement `CollectionType` — but I get nervous thinking through the implementation because it seems at least a little awkward to structure the internal API in a robust way, while also having so many types all defined in the same file.</div><div><br></div><div>I’m not entirely sold that `local` is the ideal solution, but it’s definitely addressing an IMHO significant problem.</div><div><br></div><div>What does concern me about `local` is that, at present, it would seemingly force an unnatural code organization at times; the norm is typically to put each adopted protocol into its own extension, but this means that any stored fields must either be `private` — and thus not protected by `local` — or you have to implement a lot of things from within the main definition (not idiomatic).</div><div><br></div><div>Even then, consider a simple case like this:</div><div><br></div><div>public struct SomeCustomIndex<T> {</div><div> local let position: Position</div><div>}</div><div><br></div><div>public func ==<T>(lhs: SomeViewIndex<T>, rhs: SomeViewIndex<T>) -> Bool {</div><div> return lhs.position == rhs.position // oops!</div><div>}</div><div><br></div><div>…(in this case it’s hard to see what harm you could do with `private let position`, but it illustrates a general limit to the utility of `local` declarations).</div></div></div><div style="word-wrap:break-word"><div><div><br></div><blockquote type="cite"><div><div style="word-wrap:break-word"><ul style="padding:0px 0px 0px 2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)"><li>Is the problem being addressed significant enough to warrant a change to Swift?</li></ul></div></div></blockquote></div></div><div style="word-wrap:break-word"><div><div>Yes, VERY MUCH SO.</div></div></div><div style="word-wrap:break-word"><div><div><br></div><blockquote type="cite"><div><div style="word-wrap:break-word"><ul style="padding:0px 0px 0px 2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)"><li>Does this proposal fit well with the feel and direction of Swift?</li></ul></div></div></blockquote></div></div><div style="word-wrap:break-word"><div><div>I’m not sure. I feel like there should be some better approach to visibility that solves this problem and is overall more “Swift”, but I don’t know what it is.</div></div></div><div style="word-wrap:break-word"><div><br><blockquote type="cite"><div><div style="word-wrap:break-word"><ul style="padding:0px 0px 0px 2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)"><li>If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?</li></ul></div></div></blockquote></div></div><div style="word-wrap:break-word"><div><div>I think the closest analogy here is that "private + local" are trying to get Swift to the same place that, say, “protected + friend” would get it, but along a different route.</div><div><br></div><div>The general problem being solved is that Swift’s somewhat-unique approach to `private` is unsatisfactory for some cases—IMHO in particular for the “family of related types” scenario—and `local` adds another tool to solve it.</div><div><br></div><div>Although I’m well aware of the arguments against “protected (+ friend)”, I’d point out that those constructs are IMHO the *usual* approach to solving these same issues.</div></div></div><div style="word-wrap:break-word"><div><div><br></div><br><blockquote type="cite"><div><div style="word-wrap:break-word"><ul style="padding:0px 0px 0px 2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:'Helvetica Neue',Helvetica,'Segoe UI',Arial,freesans,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)"><li>How much effort did you put into your review? A glance, a quick reading, or an in-depth study?</li></ul></div></div></blockquote></div></div><div style="word-wrap:break-word"><div></div><div>Read the proposal, participated in original discussion, read the current discussion.</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>