[swift-evolution] [Review] SE-0025 Scoped Access Level
Ilya Belenkiy
ilya.belenkiy at gmail.com
Sat Feb 27 10:20:52 CST 2016
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.
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.
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.
On Sat, Feb 27, 2016 at 10:27 AM plx via swift-evolution <
swift-evolution at swift.org> wrote:
>
> - What is your evaluation of the proposal?
>
> 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).
>
> 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.
>
> 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.
>
> 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).
>
> 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.
>
> 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)
> :
>
> @implementation PointArray {
> float *_bufferA;
> float *_bufferB;
> float *_bufferC;
> }
>
> @property(nonatomic, assign) PointArrayState state;
>
> @end
>
> …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).
>
> 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.
>
> 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.
>
> I’m not entirely sold that `local` is the ideal solution, but it’s
> definitely addressing an IMHO significant problem.
>
> 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).
>
> Even then, consider a simple case like this:
>
> public struct SomeCustomIndex<T> {
> local let position: Position
> }
>
> public func ==<T>(lhs: SomeViewIndex<T>, rhs: SomeViewIndex<T>) -> Bool {
> return lhs.position == rhs.position // oops!
> }
>
> …(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).
>
>
> - Is the problem being addressed significant enough to warrant a
> change to Swift?
>
> Yes, VERY MUCH SO.
>
>
> - Does this proposal fit well with the feel and direction of Swift?
>
> 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.
>
>
> - If you have used other languages or libraries with a similar
> feature, how do you feel that this proposal compares to those?
>
> 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.
>
> 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.
>
> 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.
>
>
>
> - How much effort did you put into your review? A glance, a quick
> reading, or an in-depth study?
>
> Read the proposal, participated in original discussion, read the current
> discussion.
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160227/fe7e350f/attachment.html>
More information about the swift-evolution
mailing list