<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="">Thank you for taking the time to provide this feedback! <div class=""><br class=""></div><div class="">I was trying to focus more on the problem we need to solve and just quickly sketch something that would solve it by building on the previous proposal. I agree the syntax (and likely semantics) left a lot to be desired and should be vastly improved. I was primarily demonstrating that is *possible* to solve the problem, we just need to find the right solution. </div><div class=""><br class=""></div><div class="">I’m glad to hear you also believe it’s a problem worth solving and just didn’t like specific details of the solution. I do think it’s worth solving the more general problem even though a good solution may be more difficult to find. If we adopt a simpler solution like the one you propose for default initializers it is likely to significantly constrain our options for solving the more general problem (in order to play nice with the simpler solution you propose).</div><div class=""><br class=""></div><div class="">I also believe that this problem is intimately related to the problem addressed in the “<font face="Helvetica Neue" class="">setup closures” thread as a general solution would supersede the need for “setup closures".</font></div><div class=""><font face="Helvetica Neue" class=""><br class=""></font></div><div class="">I would like to try coming at this problem from a different angle and see if that solution feels any better to us. Let’s consider an @initializable attribute for members:</div><div class=""><br class=""></div><div class="">@initializable members that are set by the initializer are not generated as parameters by the compiler as the body of the initializer is taking responsibility for initializing that member. The initializer is free to manually declare the a parameter with the name of the member it is initializing and use that if desired but it is not required to do so. This will ensure boilerplate still works as expected when a programmer provides it.</div><div class=""><br class=""></div><div class="">@initializable members not set in the implementation of an initializer are generated as parameters automatically by the compiler at the end of the argument list (but before any variadic or trailing closure arguments) in the order the members are declared in the type itself. If the member declares a default value, the compiler uses that as the default value for the argument. Ideally the caller can re-order the labeled arguments as desired.</div><div class=""><br class=""></div><div class="">Private members are allowed to be @initializable and may be exposed through internal or public initializers. The member itself is still hidden outside the scope of the file but any internal or public initializers should still be able to accept an initial value from a caller if desired, just as is possible with manual boilerplate today.</div><div class=""><br class=""></div><div class="">The general form of an initializer with automatically generated parameters would look something like this:</div><div class=""><br class=""></div><div class=""><div class="">init() {</div><div class=""> // Compiler generated code to set the members for which it generated parameters.</div><div class=""><br class=""></div><div class=""> // The initializer is now free to access the value proved by the caller by accessing the member which has now been initialized by the compiler generated code.</div><div class=""><br class=""></div><div class=""> // The initializer sets any members it needs to directly.</div><div class=""> // This includes all members not marked @initializable that do not have default values.</div><div class="">}</div></div><div class=""><br class=""></div><div class="">There are probably some additional details to work out in relative to two-phase initialization of classes, but I think this conveys the basic idea. </div><div class=""><br class=""></div><div class="">Here is an example:</div><div class=""><br class=""></div><div class="">struct S {</div><div class=""> @initializable let i: Int</div><div class=""> @initializable private let s: String = “s”</div><div class=""> let f: Float = 1</div><div class=""> let d: Double</div><div class=""><br class=""></div><div class=""> // i must be provided by the caller</div><div class=""> // s may be provided by the caller but is not required as there is a default value of “s”</div><div class=""> // f may be initialized directly but does not need to be as there is a default value of 1</div><div class=""> // d must be initialized directly by the initializer</div><div class=""> // callers see init(i: Int, s: String = “s")</div><div class=""> init() {</div><div class=""> // the initializer is free to read both i and s as the compiler automatically initializes them </div><div class=""> // with the value provided by the caller or the default value before the body of the initializer is entered</div><div class=""> d = Double(i)</div><div class=""> // f is initialized by the compiler to its default value</div><div class=""> }</div><div class=""><br class=""></div><div class=""> // s may be provided by the caller but is not required as there is a default value of “s”</div><div class=""> // callers see init(i: Int, j: Int, d: Double, s: String = “s")</div><div class=""><div class=""> init(i: Int, j: Int, d: Double) {</div><div class=""> // the initializer is free to read s as the compiler automatically initializes it automatically</div><div class=""> // with the value provided by the caller or the default value before the body of the initializer is entered</div><div class=""> // this initializer may not read the value of i because the compiler does not automatically generate </div><div class=""> // an initializer for it as is initialized directly</div><div class=""><br class=""></div><div class=""> // the i parameter does not need to be used to directly initialize self.i and can be used to perform computation</div><div class=""> // if desired in order to provide backwards compatibility with existing code</div><div class=""> self.i = i + j</div><div class=""> self.d = d</div><div class=""> // f is initialized by the compiler to its default value</div><div class=""> }</div></div><div class="">}</div><div class=""><font face="Helvetica Neue" class=""><br class=""></font><div class="">One drawback to a solution like this is that it could result in the compiler generating parameters for an initializer that the developer did not intend but “forgot" to initialize directly. </div><div class=""><br class=""></div><div class="">When it does so for a member that does not contain a default value, tests and calling code should fail to compile calling attention to the problem. In this case the problem is not too severe. </div><div class=""><br class=""></div><div class="">On the other hand, if the member declares a default value calling code would still compile and the member would be initialized to the default value. This is identical to the behavior of member not marked @initializable that a developer “forgets” to initialize if it declares a default value (i.e. the correct behavior for the initializer would require a value different than the default). The primary difference is the compiler generated parameter for the @initializable member that the implementer “forgot” to initialize, potentially allowing a caller to provide a value and initialize the instance in an incorrect way that is *different* than the default value which should not have been used by the initializer.</div><div class=""><br class=""></div><div class="">Another drawback to this approach is that it is not explicitly clear when reading an initializer’s parameter list. One way to mitigate this would be to require the initializer itself to be marked with @initializable in order to opt-in to the compiler generated parameters. This at least alerts the reader that they exist. It provides less information than the "init default()” approach as some @initializable members might be initialized directly in the initializer body which would suppress the compiler generated parameter. However, the semantics of @initializable are pretty straightforward so I don’t think this would cause too much confusion.</div><div class=""><br class=""></div><div class="">Documentation generated for the initializer, autocomplete, etc would all expose the full parameter including the parameters the compiler generated for @initializable members.</div><div class=""><br class=""></div><div class="">I would like to revisit the Player example to see how it would fare using this approach:</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""></blockquote> class Player {<br class=""><blockquote type="cite" class=""></blockquote> @initializable var name: String<br class=""><blockquote type="cite" class=""></blockquote> @initializable private(set) var points: Int</div><div class=""><blockquote type="cite" class=""></blockquote><font color="#5856d6" class=""><br class=""></font><blockquote type="cite" class=""></blockquote> func addPoints(additionalPoints: Int) {<br class=""><blockquote type="cite" class=""></blockquote> points += additionalPoints<br class=""><blockquote type="cite" class=""></blockquote> }<br class=""><blockquote type="cite" class=""></blockquote><font color="#5856d6" class=""><br class=""></font> // the previous post stated ‘Creates init(name: String, score: Int)' which does not match the members</div><div class=""> // this has been modified to match the members as was likely intended</div><div class=""><blockquote type="cite" class=""></blockquote> // Creates init(name: String, points: Int) </div><div class=""><blockquote type="cite" class=""></blockquote> init() {}<br class=""> }<br class=""></div><div class=""><br class=""></div><div class="">later in Player’s life:</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""></blockquote> class Player {<br class=""><blockquote type="cite" class=""></blockquote> let syncIdentifier = NSUUID()<br class=""><blockquote type="cite" class=""></blockquote> var name: String<br class=""><blockquote type="cite" class=""></blockquote> private var pointChanges: Set<PointChange><br class=""><blockquote type="cite" class=""></blockquote><font color="#5856d6" class=""><br class=""></font><blockquote type="cite" class=""></blockquote> var points: Int {<br class=""><blockquote type="cite" class=""></blockquote> get { return pointChanges.reduce(0, combine: +) }<br class=""><blockquote type="cite" class=""></blockquote> }<br class=""><blockquote type="cite" class=""></blockquote><font color="#5856d6" class=""><br class=""></font><blockquote type="cite" class=""></blockquote> func addPoints(additionalPoints: Int) {<br class=""><blockquote type="cite" class=""></blockquote> pointChanges.insert(PointChange(offset: additionalPoints)<br class=""><blockquote type="cite" class=""></blockquote> }<br class=""><blockquote type="cite" class=""></blockquote><font color="#5856d6" class=""><br class=""></font><blockquote type="cite" class=""></blockquote> // We can no longer use the compiler generated parameters, but we can still create an initializer with the same signature.</div><div class=""> // Furthermore, if we do not need to be concerned about the declaration order of keyword arguments</div><div class=""> // we can now leave off the boilerplate for “name” and allow the compiler to generate it</div><div class=""> // without requiring any changes to call sites.</div><div class=""><blockquote type="cite" class=""></blockquote> init(name: String, points: Int) {</div><div class=""><blockquote type="cite" class=""></blockquote> self.name = name<br class=""><blockquote type="cite" class=""></blockquote> pointChanges = [ PointChange(offset: points) ] // the original post had score here which did not match the parameter name<br class=""><blockquote type="cite" class=""></blockquote> }<br class=""> }</div><div class=""><br class=""></div><div class="">Does this solution look any better to you than the previous idea?</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Dec 5, 2015, at 4:31 PM, Brent Royal-Gordon <<a href="mailto:brent@architechies.com" class="">brent@architechies.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><blockquote type="cite" class="">Did you read through by reply to the original proposal? I believe it provides the convenience you're looking for here while still allowing for the flexibility to avoid boilerplate in initializers that do more than just set properties. <br class=""></blockquote><br class="">I did, and I didn’t really like it. One of the syntaxes it proposed was strange and ad-hoc; the other was a fairly arbitrary overloading of parentheses, although it doesn’t actually conflict with anything since you can’t overload “calling parentheses” on a non-function.<br class=""><br class="">It’s important to ensure that, when the implementation evolves, you can replace the initializer transparently. For instance, suppose I have a type which represents a player in a game. It uses a stored property called `points`:<br class=""><br class=""> class Player {<br class=""> var name: String<br class=""> private(set) var points: Int<br class=""><br class=""> func addPoints(additionalPoints: Int) {<br class=""> points += additionalPoints<br class=""> }<br class=""><br class=""> // Creates init(name: String, score: Int)<br class=""> init default()<br class=""> }<br class=""><br class="">Later, I decide to add syncing, and realize I need to change this model. I need to add a sync identifier, and I want to change `points` to be computed from a series of `PointChange` objects. (This is a common strategy to avoid sync conflicts.) However, I don’t want to disrupt any of my existing code when I do this.<br class=""><br class=""> class Player {<br class=""> let syncIdentifier = NSUUID()<br class=""> var name: String<br class=""> private var pointChanges: Set<PointChange><br class=""><br class=""> var points: Int {<br class=""> get { return pointChanges.reduce(0, combine: +) }<br class=""> }<br class=""><br class=""> func addPoints(additionalPoints: Int) {<br class=""> pointChanges.insert(PointChange(offset: additionalPoints)<br class=""> }<br class=""><br class=""> // We can no longer use init default(), but we can still create an initializer with the same signature<br class=""> init(name: String, points: Int) {<br class=""> self.name = name<br class=""> pointChanges = [ PointChange(offset: score) ]<br class=""> }<br class=""> }<br class=""><br class="">By *not* separating the properties into a different syntactical construct from the constructor parameters, I can update my type’s implementation without affecting its interface. If properties were separated syntactically from constructor parameters as you proposed, it would not be possible to change this seamlessly.<br class=""><br class=""><blockquote type="cite" class="">If you believe we should have a feature focused strictly on memberwise initializers and not also allow for less boilerplate in more sophisticated initializers I am interested to hear your rationale.<br class=""></blockquote><br class="">Honestly, I would like to fix the boilerplate issue in more sophisticated initializers, but I don’t see a clean way to do that. The other proposals I’ve seen in this thread, along the lines of:<br class=""><br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>init(self.name, self.points) {}<br class=""><br class="">Frankly do too much violence to the parameter list. Swift’s declarations have a lovely feature where the declaration basically looks like the usage, except that the concrete values in the usage are replaced by types in the declaration. These proposals destroy that property—when I look at the declaration, I can no longer envision what the call site will look like.<br class=""><br class="">Basically, I focused on default initializers because they’re *really* easy to solve and cover a good portion of the common case. I really have no idea how to solve the larger problem, and I haven’t liked any of the other ideas in this thread, but I do know how to solve this more limited problem.<br class=""><br class="">-- <br class="">Brent Royal-Gordon<br class="">Architechies<br class=""><br class=""></div></blockquote></div><br class=""></div></div></body></html>