<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=""><br class=""><div><blockquote type="cite" class=""><div class="">On Dec 22, 2015, at 12:08 AM, David Owens II <<a href="mailto:david@owensd.io" class="">david@owensd.io</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">I really like the idea and it’s something that’s extremely annoying to deal with today in Swift. My biggest concern is that the proposal, in its entirety, seems to really complicate the initialization rules.</div></div></blockquote><div><br class=""></div><div>Hi David. I’m glad that you like the basic idea. Thanks for taking the time to respond and offer feedback.</div><div><br class=""></div><div>The proposal as written was only intended to be a place to start a conversation. I expected it to be revised and am already in the process of doing that. Chris had some great feedback that I am taking into account. I hope both of you see the changes as improvements to the current draft.</div><div><br class=""></div><div>I looked at the approach you are suggesting and discussed something similar to it in the alternatives section. The problem with this approach is that it doesn’t address the fundamental problem I am trying to solve - namely that trivial code grows with MxN complexity (M memberwise initializable properties and N initializers). </div><div><br class=""></div><div>Your approach reduces the trivial code by about 50% but it does not address the scaling problem. Scaling isn’t really significant in small struct examples but it would be quite non-trivial in something like a Swift UIKit.</div><div><br class=""></div><div>You mentioned how your approach addresses private properties. I did consider allowing parameters to be synthesized for lower access level members. The property wouldn’t be visible, but a parameter could still be synthesized to initialize the member. I decided against this approach because I believe it is probably relatively uncommon to want to initialize a member not visible to the caller with a value provided directly by the caller. I will update the alternatives considered section to address this.</div><div><br class=""></div><div>I would also like to point out:</div><div>1) Nothing in my proposal prevents you from taking full control of the signature for your initializer. You just need to write the assignments manually.</div><div>2) What you are proposing and what I am proposing are not mutually exclusive. It would be possible for them to exist side-by-side in the language. </div><div><br class=""></div><div>Matthew</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""></div><div class="">Also, I don’t think it generates good API signatures. Take this example:</div><div class=""><br class=""></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Menlo" class="">struct S {</font></div></div><div class=""><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>let s: String</font></div></div><div class=""><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>let i: Int</font></div></div><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div><div class=""><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>// user declares:</font></div></div><div class=""><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>memberwise init() {}</font></div></div><div class=""><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>// compiler synthesizes:</font></div></div><div class=""><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>init(s: String, i: Int) {</font></div></div><div class=""><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space:pre">                </span>self.s = s</font></div></div><div class=""><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space:pre">                </span>self.i = i</font></div></div><div class=""><div class=""><font face="Menlo" class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</font></div></div><div class=""><div class=""><font face="Menlo" class="">}</font></div></div></blockquote><div class=""><div class=""><div class=""><br class=""></div><div class="">That is not a very descriptive API. It’s also not necessarily the case that your internal names are what you want exposed.</div><div class=""><br class=""></div><div class="">I would actually prefer the rule to simply be this: when an init() is modified by <i class="">memberwise</i>, the labelled parameters will be set. This lookup will try both the argument name and the parameter name, in that order, for reasons that become more clear with convenience inits described later.</div><div class=""><br class=""></div><div class="">So you would have this:</div><div class=""><br class=""></div></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><div class=""><font face="Menlo" class="">memberwise init(name s: String, value i: Int) {</font></div></div></div><div class=""><font face="Menlo" class=""> // autogenerated: self.s = s; self.i = i</font></div><div class=""><span style="font-family: Menlo;" class="">}</span></div></blockquote><div class=""><div class=""><div class=""><br class=""></div><div class="">This provides you all of the freedom that you may need:</div><div class=""><ol class="MailOutline"><li class="">Order of the APIs is explicitly controlled</li><li class="">API names of the members are not exposed if not desired, especially helpful for non-public members</li><li class="">Default values are handled naturally</li></ol><div class=""><br class=""></div></div><div class="">Optionally, you could keep the default simply with this:</div><div class=""><br class=""></div></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><div class=""><div class=""><font face="Menlo" class="">memberwise init {}</font></div></div></div></div></blockquote><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div><div class="">This would use the property names as the argument labels.</div><div class=""><br class=""></div><div class="">Another example:</div><div class=""><br class=""></div><div class=""><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div class=""><font face="Menlo" class="">memberwise init(name s: String, value i: Int = 12) {</font></div><div class=""><font face="Menlo" class=""> // autogenerated: self.s = s; self.i = i</font></div><div class=""><font face="Menlo" class="">}</font></div></blockquote><div class=""><div class=""></div></div></div><div class=""><br class=""></div><div class="">And the usage is much nicer:</div><div class=""><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><div class=""><font face="Menlo" class="">let s = S(name: "Happy")</font></div></div></div></blockquote><div class=""><div class=""><br class=""></div><div class="">Here’s a subclassing example:</div><div class=""><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Menlo" class="">class Animal {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> let type: String</font></div></div><div class=""><div class=""><font face="Menlo" class=""> let numberOfLegs: Int</font></div></div><div class=""><div class=""><font face="Menlo" class=""> </font></div></div><div class=""><div class=""><font face="Menlo" class=""> memberwise init(type: String, numberOfLegs: Int) {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> /* generated */ self.type = type</font></div></div><div class=""><div class=""><font face="Menlo" class=""> /* generated */ self.numberOfLegs = numberOfLegs</font></div></div><div class=""><div class=""><font face="Menlo" class=""> }</font></div></div><div class=""><div class=""><font face="Menlo" class="">}</font></div></div><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div><div class=""><div class=""><font face="Menlo" class="">class Dog: Animal {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> let name: String</font></div></div><div class=""><div class=""><font face="Menlo" class=""> </font></div></div><div class=""><div class=""><font face="Menlo" class=""> memberwise private init(type: String = "dog", numberOfLegs: Int = 4, n name: String) {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> /* generated */ self.name = name</font></div></div><div class=""><div class=""><font face="Menlo" class=""> /* generated */ super.init(type: type, numberOfLegs: numberOfLegs);</font></div></div><div class=""><div class=""><font face="Menlo" class=""> }</font></div></div><div class=""><div class=""><font face="Menlo" class=""> </font></div></div><div class=""><div class=""><font face="Menlo" class=""> memberwise convenience init(name: String) {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> /* generated */ self.init(type: "dog", numberOfLegs: 4, n: name)</font></div></div><div class=""><div class=""><font face="Menlo" class=""> }</font></div></div><div class=""><div class=""><font face="Menlo" class="">}</font></div></div></blockquote><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div><div class=""><div class=""><font face="Menlo" class="">let d = Dog(name: "Fido")</font></div></div></blockquote><div class=""><div class=""><br class=""></div><div class="">The biggest thing about convenience inits is that the generation of the init needs to pull the defaults from the designated init. Also, for super.init(), it’s a straight label/name lookup for the <i class="">designated</i> init() only. Anything more fancy must be written by the user.</div><div class=""><br class=""></div><div class="">You also disallow private init, but that doesn’t need to happen with explicit members. That’s the beauty of giving the public API a real contract with names.</div><div class=""><br class=""></div></div><blockquote style="margin: 0 0 0 40px; border: none; padding: 0px;" class=""><div class=""><div class=""><font face="Menlo" class="">struct S {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> let s: String</font></div></div><div class=""><div class=""><font face="Menlo" class=""> private let i: Int</font></div></div><div class=""><div class=""><font face="Menlo" class=""> </font></div></div><div class=""><div class=""><font face="Menlo" class=""> memberwise init(name s: String, value i: Int = 12) {</font></div></div><div class=""><div class=""><font face="Menlo" class=""> /* generated */ self.s = s</font></div></div><div class=""><div class=""><font face="Menlo" class=""> /* generated */ self.i = i</font></div></div><div class=""><div class=""><font face="Menlo" class=""> }</font></div></div><div class=""><div class=""><font face="Menlo" class="">}</font></div></div></blockquote><div class=""><div class=""><br class=""></div><div class="">Also, partial initialization <i class="">could</i> be possible, much like you proposed originally:</div><div class=""><br class=""></div><div class=""><div class=""><font face="Menlo" class="">struct S {</font></div><div class=""><font face="Menlo" class=""> let s: String</font></div><div class=""><font face="Menlo" class=""> private let i: Int</font></div><div class=""><font face="Menlo" class=""> </font></div><div class=""><font face="Menlo" class=""> memberwise init(name s: String) {</font></div><div class=""><font face="Menlo" class=""> /* generated */ self.s = s</font></div><div class=""><font face="Menlo" class=""> self.i = s.utf8.count</font></div><div class=""><font face="Menlo" class=""> }</font></div><div class=""><font face="Menlo" class="">}</font></div></div><div class=""><br class=""></div><div class="">My concern is that this starts to be more complicated and magical. I’d actually cut this from the proposal.</div><div class=""><br class=""></div><div class="">The last change I would make is that if any property has an assignment in the declaration, it cannot be memberwise initialized.</div><div class=""><br class=""></div><div class=""><blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;" class=""><div class=""><font face="Menlo" class="">struct S {</font></div><div class=""><font face="Menlo" class=""> let s: String</font></div><div class=""><font face="Menlo" class=""> let i: Int = 10</font></div><div class=""><font face="Menlo" class=""> </font></div><div class=""><font face="Menlo" class=""> memberwise init(name s: String) {</font></div><div class=""><font face="Menlo" class=""> /* generated */ self.s = s</font></div><div class=""><span style="font-family: Menlo;" class=""> }</span></div><div class=""><font face="Menlo" class="">}</font></div></blockquote><div class=""></div></div><div class=""><br class=""></div><div class="">In the above, <i class="">i </i>will always be 10.</div><div class=""><br class=""></div><div class="">-David</div><div class=""><br class=""></div><div class=""><div class=""><blockquote type="cite" class=""><div class="">On Dec 21, 2015, at 11:32 AM, Matthew Johnson 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=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">I have completed a draft of the proposal I have been working on for flexible memberwise initialization. I am really looking forward to your input and will be refining the proposal based on our discussion.<div class=""><br class=""></div><div class="">I am including a current snapshot of the proposal in this message. I will keep the proposal up to date on Github at this link:</div><div class=""><br class=""></div><div class=""><a href="https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md" class="">https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md</a></div></div></div></blockquote></div><br class=""></div></div></div></div></blockquote></div><br class=""></body></html>