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.
Sometimes, trying to break apart a large type using extensions, I
encounter this pattern:
class Thingamer {
private var doodads: [Doodad]
// All of these use the doodads var:
public func mangleDoodads() { … }
public func fungeDoodads() { … }
public func renoberateDoodads() { … }
private func doodadHelper() { … }
// …and no other methods touch it
}
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.
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”.
It would be nice if Swift extensions let us encapsulate state+behavior
relationships without having to create new type boundaries.
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?
Cheers,
Paul
On Sep 10, 2016, at 11:28 AM, Xiaodi Wu via swift-evolution < > swift-evolution@swift.org> wrote:
Agreed.
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.
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).
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.
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.
On Sat, Sep 10, 2016 at 09:31 Nevin Brackett-Rozinsky via swift-evolution < > swift-evolution@swift.org> wrote:
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.
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.
Count me as opposed to any sort of “class scoped” access level.
Nevin
On Sat, Sep 10, 2016 at 10:01 AM, Rien via swift-evolution < >> swift-evolution@swift.org> wrote:
> On 10 Sep 2016, at 14:16, T.J. Usiyan via swift-evolution < >>> swift-evolution@swift.org> wrote:
>
> I am firmly against this. The 5 levels that we have cover us well and
have enough complexity already.
Agree.
> On Sat, Sep 10, 2016 at 5:23 AM, Tom Bates via swift-evolution < >>> swift-evolution@swift.org> wrote:
> I agree that classprivate would probably not work, maybe
constructprivate? but then you are leaving our enum etc.
> 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?`
> 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.
>
> 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.
>
> Suggestions so far:
> `classprivate`
> `constructprivate`
> `private(instance)`, `private(instance, set)` - problem -> how would
this work? `public private(instance, set)`
> `internal(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.
>
>
> On Sat, 10 Sep 2016 at 07:09 Adrian Zubarev via swift-evolution < >>> swift-evolution@swift.org> wrote:
> 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.
>
> --
> Adrian Zubarev
> Sent with Airmail
> Am 9. September 2016 um 19:09:12, Xiaodi Wu (xiaodi.wu@gmail.com)
schrieb:
>
>> 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.
>>
>>
>> On Fri, Sep 9, 2016 at 11:34 AM, Adrian Zubarev via swift-evolution < >>> swift-evolution@swift.org> wrote:
>> 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.
>>
>> 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)!
>>
>>
>> --
>> Adrian Zubarev
>> Sent with Airmail
>> Am 9. September 2016 um 17:49:29, Tom Bates via swift-evolution (
swift-evolution@swift.org) schrieb:
>>
>>> There is currently no way of accessing "shared code" from extensions
declared outside the base .swift file
>>>
>>> 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.
>>>
>>> an example is below...
>>>
>>> =================
>>> //MyClass.swift
>>> public class MyClass {
>>>
>>> classprivate func sharedFunction() {
>>> self.function1()
>>> self.function2()
>>> }
>>>
>>> fileprivate func function1() {}
>>> fileprivate func function2() {}
>>> }
>>> =================
>>>
>>> =================
>>> //MyClass+Save.swift
>>> extension MyClass {
>>>
>>> public func save() {
>>> self.someFunction()
>>> self.sharedFunction()
>>> }
>>>
>>> fileprivate func someFunction() {}
>>> }
>>> =================
>>>
>>> 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.
>>>
>>> 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
>>>
>>> Regards,
>>> Tom
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution@swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution