[swift-evolution] [Proposal Draft] Flexible memberwise initialization

Chris Lattner clattner at apple.com
Sat Dec 26 23:31:07 CST 2015


On Dec 25, 2015, at 12:04 PM, Matthew Johnson <matthew at anandabits.com> wrote:
>>> Discussion on a couple of topics continues inline below as well.
>> 
>> Great, comments below:
> 
> Thanks for continuing the discussion.  I have updated the proposal to reflect the core functionality and moved everything else to the future enhancements section.  I think this draft is ready or nearly ready for a PR.
> 
> Here is a link to the current draft: https://github.com/anandabits/swift-evolution/edit/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md <https://github.com/anandabits/swift-evolution/edit/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md>
> 
> Here is a link to the commit diff: https://github.com/anandabits/swift-evolution/commit/f15360d2e201709640f9137d86a8b705a07b5466?short_path=f5ec377#diff-f5ec377f4782587684c5732547456b70 <https://github.com/anandabits/swift-evolution/commit/f15360d2e201709640f9137d86a8b705a07b5466?short_path=f5ec377#diff-f5ec377f4782587684c5732547456b70>
Thanks again for pushing this forward, this is looking great.

>> It is also annoying that writing it as a static property would force you to write something like “X.a" instead of just “a”.
> 
> I agree with this.  I can accept an argument that this provides enough value to avoid changing the language.
> 
> That said, I do think default values for let properties are higher value.  If I had to pick one it would be default values and I would consider it to be worthy of a breaking change in the language.  But It would be great if we can find a way to support both.

I understand your desire, but this really is something we’ll have to discuss carefully.  Changing Swift soft that “let x = 42” doesn’t necessarily mean that x is 42 is a pretty deep semantic change, which will be surprising for many people (as was noted by others on this thread).  I agree that it would be great to get more flexible initialization for lets, but keep in mind that you can already do this long-hand if you want.

>> This I still have a concern with, in two ways:
>> 
>> 1) This still has tight coupling between the base and derived class.  Properties in a based class are not knowable by a derived class in general (e.g. across module boundaries) and this directly runs afoul of our resilience plans.  Specifically, across module boundaries, properties can change from stored to computed (or back) without breaking clients.
>> 
>> 2) You’re introducing another unnecessary feature "super.init(…)” which will have to be independently justified. 
>> 
> 
> I will continue thinking about how this might be solved and also about other cases where such a forwarding feature might be useful.  

Sounds good.  This is definitely an interesting area to investigate, but I don't want the general goodness of your base memberwise init proposal to have to wait :-)

>> Other comments:
>> 
>> In "Impact on existing code”, given your proposal, I think that we should keep the implicit memberwise initializer on classes, start generating it for root classes, and generate it for derived classes whose parent has a DI with no arguments (e.g. subclasses of NSObject).  We should keep the current behavior where it is generated with internal behavior, and it is surpressed if *any* initializers are defined inside of the type.
> 
> I’ll update that section to reflect these comments.  
> 
> One question I have is what the implicit memberwise initializer should do in the case of private members.  If we make it follow the rules of this proposal we would break existing structs with private members that are currently receiving the implicit memberwise initializer.  
> 
> I think this would be a good breaking change for both consistency with this proposal and because implicitly exposing private members via the initializer was a questionable choice.  A mechanical migration could generate code to add an explicit implementation of the previously implicit initializer that doesn’t qualify under the rules of the new proposal.  How do you feel about this?

I don’t have a strong opinion about this, and I can see reasonable arguments on either side.  Breaking source compatibility in this case isn’t a show-stopper, since this will roll out in Swift 3.

Here are the pros and cons as I see them with disallow-ing more-private fields to be published through less-private memberwise inits:

Neutral: Either approach is fine for “CGRect” like types that are really just public bags of public fields.
Pro: Makes logical sense at first blush.  Memberwise inits publishing private state would be odd/surprising.
Pro: Safer default, in that you don’t accidentally publish stuff you don’t want through a memberwise init.
Con: This puts tension between access control for stored properties and memberwise inits.  You have to choose between narrower access control or getting the benefit of a memberwise init.  Another way to say it: this design means that narrow access control leads to boilerplate.

I’m sure there are others as well.

Again, I don’t have a strong opinion, but I’d lean slightly towards publishing all stored properties through the memberwise init.  If you don’t have a strong opinion either, it would be fine to add a section pointing out the tradeoffs, and we can all discuss it during the review period.  I suspect some of the other core team folks will have an opinion on this as well.

I sent you a PR (my first! :-) with some nit-picky details on the latest writeup, to fix typos, clarify a few things, and reduce redundancy.  One point that I left:

> The *implicitly* synthesized initializer will be identical to an initializer declared *explicitly* as follows:
> 
> 1. For structs and root classes: `memberwise init(...) {}`
> 2. For derived classes: `memberwise init(...) { super.init() }`

Note that these are both equivalent, since derived class initializers default to super.init() at the bottom of their body today.  This is why you don’t have to call super.init() when deriving from NSObject, for example.


>> Thanks again for pushing this forward, you can also put me down as the review manager if you’d like.
>> 
> 
> You’re very welcome.  It’s a privilege to be able to contribute ideas, have them taken seriously and hopefully see them lead to progress in the language.  I’ve really enjoyed the process and discussions with the core team as well as the broader community.
> 
> It’s really incredible to see the Swift team embrace the community so openly and so graciously!
> 
> Merry Christmas!

You too Matthew, thanks again,

-Chris

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151226/ddf9dd37/attachment.html>


More information about the swift-evolution mailing list