<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 Jan 8, 2016, at 2:09 PM, David Owens II &lt;<a href="mailto:david@owensd.io" class="">david@owensd.io</a>&gt; 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=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Jan 8, 2016, at 11:21 AM, Matthew Johnson &lt;<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>&gt; 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=""><div class=""><div class=""><br class=""></div><div class="">Actually it is internal, not private, and it exposes private properties via that internal initializer. &nbsp;It’s only in your own code, but I don't think it should be violating access control in that way.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Not for me in Xcode 7.2. Has this changed? Maybe it’s my app target? The implicit init() is only visible for me within the same file the struct is defined in.</div></div></div></div></blockquote><div><br class=""></div><div>Wow, you’re right. &nbsp;It is enforcing access control. &nbsp;The implicit init is internal if there are no private properties, but private if there are private properties. &nbsp;I wonder if this has changed. &nbsp;If not, I’m embarrassed that I didn’t understand the current behavior in detail.&nbsp;</div><div><br class=""></div><div>I thought it was always internal. &nbsp;I’ve never actually used it for a struct with private properties before and I think the docs all say internal so maybe that is why. &nbsp;In any case, I’m glad to see that it is enforcing access control rules.</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=""><div class=""><br class=""></div><div class=""><br class=""></div><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=""><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="">The proposal essentially is doing two things:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; 1. Create a way to generate a public API contract based on a series of fairly complicated rules, potential annotations, and member orderings within the type</div></div></div></blockquote><div class=""><br class=""></div><div class="">Would you feel better about the proposal if it did not allow for public memberwise initializers?</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Marginally. My main concern is the complexity of the rules, especially when looking at the direction many of the futures take. There are all of these annotations that get put all over that litter the type</div></div></div></div></blockquote><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=""><div class="">definition simply to support memberwise inits.</div></div></div></div></blockquote><div><br class=""></div><div>Maybe I wasn’t clear enough, but I never intended for all of them to be accepted. &nbsp;They are intended to show different ways to allow a bit more control.</div><div><br class=""></div><div><div>The proposal only changes current state in a few ways:</div><div><br class=""></div><div>1. Allow the memberwise initializer to be used in classes</div><div>2. Allow default parameter values for `var` properties</div><div>3. Fix the problem the current memberwise initializer has with lazy properties</div><div>4. Use the `set` rather than `get` visibility for `var` properties</div><div>5. Allow you to request the memberwise initializer, including:</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>i. Specify access level, which will result in omission of memberwise parameters for more-private properties</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>ii. Add additional parameters</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>iii. include an initializer body</div><div><br class=""></div><div>Are there specific changes in this list that you dislike?</div></div><div><br class=""></div><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=""><div class=""><br class=""></div><div class=""><br class=""></div><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=""><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="">&nbsp; &nbsp; 2. Generate the pass through of assignment for the parameters of the init() and their backing values.</div><div class=""><br class=""></div><div class="">The vast amount complexity comes from trying to solve #1.</div></div></div></blockquote><div class=""><br class=""></div><div class="">This is not true. &nbsp;I would still want access control enforced even if memberwise initializers could not be public.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">There’s no concern with access control as it’s explicitly handled. I can expose whatever I want as the API and route it however I want in code.&nbsp;</div></div></div></div></blockquote><div><br class=""></div><div>I understand that this is true with your approach. &nbsp;I was responding to your statement that the source of complexity in my proposal is from trying to allow public memberwise inits (your solve #1). &nbsp;It doesn’t come from wanting to allow public inits. &nbsp;It mainly comes from enforcing access control. &nbsp;It turns out that the current implicit init is already doing that.</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=""><div class=""><br class=""></div><div class=""><br class=""></div><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=""><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="">As for this:</div><div class=""><br class=""></div><div class=""><div class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class=""><blockquote type="cite" class="">(Aside, a small nitpick, but it really bugs me:&nbsp;initialization has O(M+N) complexity, not O(M×N) complexity. One doesn’t initialize every member with every parameter.)</blockquote></div></div></div></div></blockquote><blockquote type="cite" class=""><br class=""></blockquote><div class=""><blockquote type="cite" class="">MxN is members x initializers.</blockquote></div></div></div><div class=""><br class=""></div><div class="">Paul, this has also bugged me too; I do not see how it is accurate. There aren’t N initializers, there is one initializer that must fully instantiate the type. Each type may have additional convenience initializers, but these are not required. Further, they cannot make use of the placeholder. There is a “futures” that talks about it, but that’s out of scope of the original proposal.&nbsp;</div></div></div></blockquote><div class=""><br class=""></div><div class="">Swift allows more than one designated initializer. &nbsp;N never large but it more than 1 in enough cases to matter. &nbsp;The point is that it results in enough boilerplate that I believe it affects how many people design their initializers. &nbsp;</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">Sure, but your base proposal does not allow a way for there to be more than one memberwise designated initializer. So in the base case, your proposal doesn’t solve what you call the MxN problem. In the futures, you describe ways to annotate inits() so that members aren’t considered in the signature.</div></div></div></div></blockquote><div><br class=""></div><div>My proposal does allow for more than 1 memberwise init. &nbsp;The idea is that there are different ways to init the private state. &nbsp;It also allows memberwise inits with different access control, which would possibly receive different memberwise parameters due to the access control rules.</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=""><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&nbsp;Point {</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;let&nbsp;x:&nbsp;Int</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;let&nbsp;y:&nbsp;Int</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;let&nbsp;z:&nbsp;Int</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;@nomemberwise(y, z)</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;memberwise&nbsp;init(...) {</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;y =&nbsp;0</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;z =&nbsp;0</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;}</font></div></div><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;@nomemberwise(z)</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;memberwise&nbsp;init(...) {</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;z =&nbsp;0</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;}</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp; memberwise&nbsp;init(...) {}</font></div></div></div></div><div class=""><div class=""><font face="Menlo" class="">}</font></div></div></blockquote><div class=""><div class=""><br class=""></div><div class="">Let’s say that for simplicity the @nomemberwise() attribute takes a list of parameters. This is one version of the code that can be written to support zero-ing out by default.</div><div class=""><br class=""></div><div class="">Or, we can do this (what Swift has today):</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=""><div class=""><font face="Menlo" class="">struct&nbsp;Point {</font></div></div></div></div><div class=""><div class=""><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;let&nbsp;x:&nbsp;Int</font></div></div></div></div><div class=""><div class=""><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;let&nbsp;y:&nbsp;Int</font></div></div></div></div><div class=""><div class=""><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;let&nbsp;z:&nbsp;Int</font></div></div></div></div><div class=""><div class=""><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;</font></div></div></div></div><div class=""><div class=""><div class=""><div class=""><span style="font-family: Menlo;" class="">&nbsp; &nbsp; init(x: Int, y: Int = 0, z: Int = 0) {</span></div><div class=""><span style="font-family: Menlo;" class="">&nbsp; &nbsp; &nbsp; &nbsp; self.x = x</span></div><div class=""><span style="font-family: Menlo;" class="">&nbsp; &nbsp; &nbsp; &nbsp; self.y = y</span></div><div class=""><span style="font-family: Menlo;" class="">&nbsp; &nbsp; &nbsp; &nbsp; self.z = z</span></div></div></div></div><div class=""><div class=""><div class=""><div class=""><span style="font-family: Menlo;" class="">&nbsp; &nbsp; }</span></div></div></div></div><div class=""><div class=""><div class=""><div class=""><span style="font-family: Menlo;" class="">}</span></div></div></div></div></blockquote><div class=""><div class=""><br class=""></div><div class="">Or with the below example:</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=""><div class=""><div class=""><div class=""><font face="Menlo" class="">struct&nbsp;Point {</font></div></div></div></div></div></div><div class=""><div class=""><div class=""><div class=""><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;let&nbsp;x:&nbsp;Int</font></div></div></div></div></div></div><div class=""><div class=""><div class=""><div class=""><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;let&nbsp;y:&nbsp;Int</font></div></div></div></div></div></div><div class=""><div class=""><div class=""><div class=""><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;let&nbsp;z:&nbsp;Int</font></div></div></div></div></div></div><div class=""><div class=""><div class=""><div class=""><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;</font></div></div></div></div></div></div><div class=""><div class=""><div class=""><div class=""><div class=""><div class=""><span style="font-family: Menlo;" class="">&nbsp; &nbsp; init(self x: Int, self y: Int = 0, self z: Int = 0) {</span><span style="font-family: Menlo;" class="">}</span></div></div></div></div></div></div><div class=""><div class=""><div class=""><div class=""><div class=""><div class=""><span style="font-family: Menlo;" class="">}</span></div></div></div></div></div></div></blockquote><div class=""><div class=""><br class=""></div><div class="">Even in all of your futures, I don’t see how you fix the "MxN problem" for let without bringing back the assignment in the type declaration, which was generally not well received.</div><div class=""><br class=""></div><div class=""><br class=""></div><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=""><blockquote type="cite" 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="">Your example hear illustrates the complexity (slightly modified from your proposal’s usage):</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&nbsp;</font><span style="font-family: Menlo;" class="">Foo {</span></div></div><div class=""><div class=""><span style="font-family: Menlo;" class="">&nbsp; let</span><span style="font-family: Menlo;" class="">&nbsp;bar:&nbsp;</span><span style="font-family: Menlo;" class="">String</span></div></div><div class=""><div class=""><span style="font-family: Menlo;" class="">&nbsp; let</span><span style="font-family: Menlo;" class="">&nbsp;bas:&nbsp;</span><span style="font-family: Menlo;" class="">Int</span></div></div><div class=""><div class=""><span style="font-family: Menlo;" class="">&nbsp; let</span><span style="font-family: Menlo;" class="">&nbsp;baz:&nbsp;</span><span style="font-family: Menlo;" class="">Double</span></div></div><div class=""><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">&nbsp; init(self bar: String, self bas: Int, bax:&nbsp;Int</font><span style="font-family: Menlo;" class="">) {</span></div></div><div class=""><div class=""><span style="font-family: Menlo;" class="">&nbsp; &nbsp; // self.bar = bar synthesized by the compiler</span></div></div><div class=""><div class=""><div class=""><span style="font-family: Menlo;" class="">&nbsp; &nbsp; // self.bas = bas synthesized by the compiler</span></div></div></div><div class=""><div class=""><div class=""><span style="font-family: Menlo;" class="">&nbsp; &nbsp; self</span><span style="font-family: Menlo;" class="">.</span><span style="font-family: Menlo;" class="">baz&nbsp;</span><span style="font-family: Menlo;" class="">=</span><span style="font-family: Menlo;" class="">&nbsp;</span><span style="font-family: Menlo;" class="">Double</span><span style="font-family: Menlo;" class="">(bax)</span></div></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; }</font></div></div><div class=""><div class=""><font face="Menlo" class="">}</font></div></div></blockquote></div></blockquote><div class=""><br class=""></div><div class="">This approach has been mentioned quite a few&nbsp;times. &nbsp;It results in a lot of duplication without saving a lot. &nbsp;This is especially true if you have a lot of properties and more than one designated initializer that could use memberwise initialization . &nbsp;</div><div class=""><br class=""></div><div class="">IMO, if we were going to take this approach we should at least be able to omit redundant type information and default values for `var` properties where they exist. &nbsp;At least then we are saving as much as we can under this approach.</div><div class=""><br class=""></div><div class="">struct&nbsp;Foo {<br class="">&nbsp; let&nbsp;bar:&nbsp;String<br class="">&nbsp; let&nbsp;bas:&nbsp;Int<br class="">&nbsp; let&nbsp;baz:&nbsp;Double<br class=""><br class="">&nbsp; init(self bar, self bas, bax: Int) {<br class="">&nbsp; &nbsp; // self.bar = bar synthesized by the compiler<br class="">&nbsp; &nbsp; // self.bas = bas synthesized by the compiler<br class="">&nbsp; &nbsp; self.baz&nbsp;=&nbsp;Double(bax)<br class="">&nbsp; }<br class="">}</div></div></div></div></blockquote></div><br class=""><div class="">I think it keeps coming up because it’s far simpler. While there is duplication in the type signature, the code is still smaller, more flexible, and more applicable than being limited to only initialization. Further, and I think this is what is far more important, I only need to look at single place to understand what is going on with initialization for any particular call. I don’t need to find out what members are annotated, or create the list of head of members and exclude certain ones if @nomemberize() is used. Each member being initialized as a configuration entity from the user is right there, no questions asked.</div></div></div></blockquote><div><br class=""></div><div>How is this more applicable than just for initialization? &nbsp;Are you suggesting a self parameter be allowed in any method and it would result in an immediate set of that property?</div><div><br class=""></div><div>Your critique regarding clarity is very reasonable and it is definitely the biggest drawback with the automatic model. &nbsp;A number of people have commented on both the complexity / lack of clarity as well as the limitations of the automatic model. &nbsp;The opt-in model described in the proposal has some of the same issues. &nbsp;I have started to think more about an opt-in model that would avoid all of those issues. &nbsp;</div><div><br class=""></div><div>I really appreciate the feedback and conversation. &nbsp;I am continuing to think about all of the comments and am hoping we can come out of this review with a vision for a path forward that makes most people happy whether the proposal is accepted or not. &nbsp;(I think it’s clear that no solution will make everyone happy but do hope we can hit a sweet spot)</div><div><br class=""></div><div>Matthew</div></div><br class=""></body></html>