[swift-evolution] [Proposal Draft] Flexible memberwise initialization
matthew at anandabits.com
Wed Jan 6 20:31:05 CST 2016
Sent from my iPad
> On Jan 6, 2016, at 7:57 PM, Joe Groff <jgroff at apple.com> wrote:
>> On Jan 6, 2016, at 3:39 PM, Matthew Johnson <matthew at anandabits.com> wrote:
>>> On Jan 6, 2016, at 5:08 PM, Joe Groff <jgroff at apple.com> wrote:
>>> I find it surprising that you key the initialization of 'var's based on whether their setter is visible or not. Initialization is not the same as setting, and memberwise initializers within the definition have private access to the member anyway; this is why `let` properties can be initialized, after all. `private(set)` is also a way for an API to communicate that a property is read-only without promising that it is or will always be immutable, so I think it's important that a 'private(set) var' be as capable as a 'let' to the maximum degree possible.
>> Hi Joe,
>> Thanks for bringing this topic up and moving the discussion to the list (it’s hard to get into details on Twitter).
>> I am definitely sympathetic to the points you raise. The problem is that there is no good solution to this without involving at least one of the future enhancements. Chris feels strongly that we need to focus on the core functionality for the initial proposal so we must choose a solution without them.
>> Using the `var` setter visibility is the least bad option in my mind. There are many times when a var might represent internal state that a user is allowed to read, but should never be allowed to specify, whether via initialization or otherwise. These will have `private(set)` visibility.
>> If we allow memberwise initialization to expose them it will be a useless feature for types that contain a var like this. There will not be any way to specify that they should not participate in memberwise initialization without at least one of the future enhancements. On the other hand, if you do wish to expose them via the initializer it is easy to add a parameter and initialize the `var` manually.
>> This is also a safer solution. The author of the type has specifically stated that users should not be setting the value of the `var`. Maybe that doesn’t apply to initialization, but it is not the right decision to assume that IMO, at least without the ability to specify `init` visibility independently if desired.
>> In the case of `let`, if we do not use the only access control modifier they are allowed to have they would not be able to participate in memberwise initialization at all.
>> I think the proposal makes the least bad choice we can make without expanding it to include the ability to specify init visibility (which I would support if the core team was willing to do that).
> I'm not sure what you mean by init visibility.
The proposal suggests a possible future enhancement for specifying access control for init distinct from get and set like: 'private public(init)'. This would be available to both 'let' and 'var' properties and would allow a single memberwise initialization rule to be used for all properties.
> I feel like all these arguments could also be made for 'let'; what makes a get-only var different from the initializer's perspective?
This is true in some sense. The difference is that 'let' properties only have access control for a getter making it the only option we have if they are allowed to participate in memberwise initialization.
Here's an example. Think of a progress property. That will be a far with a public getter but a private setter. It would clearly be wrong if that were exposed by an initializer. If we use the getter for a 'var' in memberwise initialization it would be exposed to all memberwise initializers under the current proposal (without any of the enhancements).
Types with properties like this are not uncommon. Memberwise initialization would be useless with these types if the getter visibility was used.
There are several ways to solve this but Chris did not want to include any of them in the initial proposal. I went with what I feel is the least bad option remaining, which is to use the setter visibility for 'var' properties.
It is least bad because it will actually be the right thing a lot of the time and because you can still use memberwise initialization for other properties when it doesn't do what you need. Using the getter would be right some of the time (less often I think, but that's just a guess) but when it isn't you would have to avoid memberwise initialization for the entire type.
It is different than 'let' properties because it has to be if we want to do the least bad thing for 'var' properties and we also want to allow 'let' properties to participate in memberwise initialization.
More information about the swift-evolution