<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">I do certainly agree that 5 access levels are _plenty_, C++ “friend” is no great friend to me, and I too not want to see another one access level added. However, I do think there’s a related problem here worth solving.</div><div class=""><br class=""></div><div class="">Sometimes, trying to break apart a large type using extensions, I encounter this pattern:</div><div class=""><br class=""></div><div class="">class Thingamer {</div><div class=""> private var doodads: [Doodad]</div><div class=""><br class=""></div><div class=""> // All of these use the doodads var:</div><div class=""><br class=""></div><div class=""> public func mangleDoodads() { … }</div><div class=""> public func fungeDoodads() { … }</div><div class=""> public func renoberateDoodads() { … }</div><div class=""> private func doodadHelper() { … }</div><div class=""><br class=""></div><div class=""> // …and no other methods touch it</div><div class="">}</div><div class=""><br class=""></div><div class="">My first instinct in this situation is to pull all the doodad-related stuff into a separate type, but sometimes that’s the wrong solution. Perhaps the public API gets messy or nonsensical if those public doodad-related methods aren’t on Thingamer. Perhaps other Thingamer methods use those doodad methods, even if they don’t use the private var. Perhaps there’s still coupling to Thingamer through other class properties. And so forth.</div><div class=""><br class=""></div><div class="">It would be great to group all the doodad-stuff into an extension. The inability of extensions to use class-private vars is the barrier. My usual solution is to make the doodads var internal, and then try to remember not to use it outside of the extension — which looks a lot like “fake friend”.</div><div class=""><br class=""></div><div class="">It would be nice if Swift extensions let us encapsulate state+behavior relationships without having to create new type boundaries.</div><div class=""><br class=""></div><div class="">IIRC, there was talk of extensions being able to add properties to an existing type. It seems like this would be feasible, at least for types within the same module? Perhaps there’s another better way?</div><div class=""><br class=""></div><div class="">Cheers,</div><div class=""><br class=""></div><div class="">Paul</div><br class=""><div><blockquote type="cite" class=""><div class="">On Sep 10, 2016, at 11:28 AM, Xiaodi Wu via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="white-space:pre-wrap" class="">Agreed.<br class=""><br class="">Swift's access levels are deliberately defined in terms of contiguous blocks of written code [this is inelegantly phrased, but I think you see what I mean]. As such, neither a "class scoped" level nor a level shared between a type and its extensions would fit in such a scheme.<br class=""><br class="">Such an addition would fundamentally counter the existing design of Swift, open the door for compensating features such as "friend classes" that (IIUC) were deliberately avoided, and fails to compose with existing access levels as inevitably there will be proposals to do. By that I mean, why should a "class scoped" member always be limited in visibility to the same module? This satisfies your particular motivating use case, but someone else will want the same kind of class scoping but also allow a member to be accessed by extensions outside the module (classpublic, if you will); still others will want a member to be overridable outside the module (classopen); for good measure, some will want access limited to only extensions and not other types in the same file (classfileprivate; it is not out of the question for someone to raise this point, since it is a close cousin of the argument for distinguishing private and fileprivate).<br class=""><br class="">If I had my druthers, it'd be nice to have exactly something like Nevin's idea, a terse way to group related files into submodules, and a keyword like `subinternal` that restricts visibility to that group of files. It would satisfy the motivating use case here while preserving the deliberate design decision that Swift access levels do not pick and choose non-contiguous chunks of multiple files.<br class=""><br class="">In any case, let's postpone this discussion until it comes into scope at a later phase of Swift evolution. The core team and other experts would no doubt have much to contribute at that time.</div><br class=""><br class=""><div class="gmail_quote"><div dir="ltr" class="">On Sat, Sep 10, 2016 at 09:31 Nevin Brackett-Rozinsky via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:<br class=""></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr" class="">Indeed, I find it rather less convenient to write “fileprivate” in many places I previously would use “private”, and unfortunate that I must choose between aggregating many pieces into a single lengthy file or else polluting the module scope with implementation details.<div class=""><br class=""></div><div class="">I agree with Xiaodi that submodules are a far cleaner design, and I would very much like to replace “fileprivate” with a short word that implies “private to the submodule”. Then by default each file could be its own submodule, and a developer could opt into having more files in a submodule if they so desire.</div><div class=""><br class=""></div><div class="">Count me as opposed to any sort of “class scoped” access level.</div></div><div dir="ltr" class=""><div class=""><br class=""></div><div class="">Nevin</div><div class=""><br class=""></div><div class=""><br class=""></div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Sat, Sep 10, 2016 at 10:01 AM, Rien via swift-evolution <span dir="ltr" class=""><<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">> On 10 Sep 2016, at 14:16, T.J. Usiyan via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:<br class="">
><br class="">
> I am firmly against this. The 5 levels that we have cover us well and have enough complexity already.<br class="">
<br class="">
</span>Agree.<br class="">
<div class=""><div class=""><br class="">
<br class="">
<br class="">
> On Sat, Sep 10, 2016 at 5:23 AM, Tom Bates via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:<br class="">
> I agree that classprivate would probably not work, maybe constructprivate? but then you are leaving our enum etc.<br class="">
> With the `internal(class)` suggestion, if declaring a var such as `internal(set) var name: String?` would this become `internal(class, set) var name: String?`<br class="">
> Also there would need to be some kind of compile check either way because if you declared an enum for example outside of a constructor you would not be able to mark it as our new constructor only access level or it would become inaccessible throughout the project.<br class="">
><br class="">
> Re: submodules, they are indeed overkill for this. As you would need a separate submodule for each class you wanted to do this with and then run the risk of inter coupling lots of different really small submodules.<br class="">
><br class="">
> Suggestions so far:<br class="">
> `classprivate`<br class="">
> `constructprivate`<br class="">
> `private(instance)`, `private(instance, set)` - problem -> how would this work? `public private(instance, set)`<br class="">
> `internal(class)`<br class="">
><br class="">
> Personally I think a name like `classprivate` or `constructprivate`, although not particularly well named would reduce complexities with private setters syntax and keep migrations much simpler.<br class="">
><br class="">
><br class="">
> On Sat, 10 Sep 2016 at 07:09 Adrian Zubarev via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:<br class="">
> I don't think submodules would solve it nicely. Each module/submodule will require it's own namespace + it feels like an overkill to create submodules for a few types. `internal(xyz)` seems to me like a better solution. And yes this is purely additional and nothing for phase 1.<br class="">
><br class="">
> --<br class="">
> Adrian Zubarev<br class="">
> Sent with Airmail<br class="">
> Am 9. September 2016 um 19:09:12, Xiaodi Wu (<a href="mailto:xiaodi.wu@gmail.com" target="_blank" class="">xiaodi.wu@gmail.com</a>) schrieb:<br class="">
><br class="">
>> Isn't the general solution to this problem submodules? In any case, seems like it'd be out of scope for Swift 4 phase 1.<br class="">
>><br class="">
>><br class="">
>> On Fri, Sep 9, 2016 at 11:34 AM, Adrian Zubarev via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:<br class="">
>> There must be a better solution to this problem, because you might also extend value types from different files. That would mean, we'd need `structprivate` `protocolprivate` etc.<br class="">
>><br class="">
>> How about: `internal(class)` etc. ? Or something like `internal(private)` to rule them all (I don't like the last name, but something that would rule them all would be nice to have)!<br class="">
>><br class="">
>><br class="">
>> --<br class="">
>> Adrian Zubarev<br class="">
>> Sent with Airmail<br class="">
>> Am 9. September 2016 um 17:49:29, Tom Bates via swift-evolution (<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>) schrieb:<br class="">
>><br class="">
>>> There is currently no way of accessing "shared code" from extensions declared outside the base .swift file<br class="">
>>><br class="">
>>> I would love to see along side the new fileprivate access level a classprivate access level that would allow any extension declared outside of the original .swift file to access these properties and functions in an attempt to reuse code.<br class="">
>>><br class="">
>>> an example is below...<br class="">
>>><br class="">
>>> =================<br class="">
>>> //MyClass.swift<br class="">
>>> public class MyClass {<br class="">
>>><br class="">
>>> classprivate func sharedFunction() {<br class="">
>>> self.function1()<br class="">
>>> self.function2()<br class="">
>>> }<br class="">
>>><br class="">
>>> fileprivate func function1() {}<br class="">
>>> fileprivate func function2() {}<br class="">
>>> }<br class="">
>>> =================<br class="">
>>><br class="">
>>> =================<br class="">
>>> //MyClass+Save.swift<br class="">
>>> extension MyClass {<br class="">
>>><br class="">
>>> public func save() {<br class="">
>>> self.someFunction()<br class="">
>>> self.sharedFunction()<br class="">
>>> }<br class="">
>>><br class="">
>>> fileprivate func someFunction() {}<br class="">
>>> }<br class="">
>>> =================<br class="">
>>><br class="">
>>> Currently to achieve anything like this you would have to make the "core" functions public or internal or write the whole thing in a single file which as I understand it is not optimal for the compile speed and can get unmanageable for large classes. This would allow a more managed file structure and the separation of related functions from the core declaration.<br class="">
>>><br class="">
>>> There would be no migration needed I don't think as the impact on current code would be zero until the developer adopts the new access level<br class="">
>>><br class="">
>>> Regards,<br class="">
>>> Tom<br class="">
>>> _______________________________________________<br class="">
>>> swift-evolution mailing list<br class="">
>>> <a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
>>> <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
>><br class="">
>> _______________________________________________<br class="">
>> swift-evolution mailing list<br class="">
>> <a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
>> <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
>><br class="">
>><br class="">
> _______________________________________________<br class="">
> swift-evolution mailing list<br class="">
> <a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
> <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
><br class="">
> _______________________________________________<br class="">
> swift-evolution mailing list<br class="">
> <a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
> <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
><br class="">
><br class="">
> _______________________________________________<br class="">
> swift-evolution mailing list<br class="">
> <a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
> <a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
<br class="">
_______________________________________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
</div></div></blockquote></div><br class=""></div>
_______________________________________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
</blockquote></div>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></body></html>