> On Dec 21, 2015, at 5:47 PM, Chris Lattner via swift-evolution > <swift-evolution@swift.org> wrote: > > On Dec 21, 2015, at 11:32 AM, Matthew Johnson via swift-evolution > <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: >> 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. >> >> 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: >> >> https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md >> >> <https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md> > This is a really really interesting approach, I really like it. Detailed > comments below, I’m skipping all the stuff I agree with or have no additional > comments on: > >> >> Flexible Memberwise Initialization >> >> <https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md#replacing-the-current-memberwise-initializer>Replacing >> the current memberwise initializer >> >> struct S { >> let s: String >> let i: Int >> >> // user declares: >> memberwise init() {} > It never occurred to me to allow a body on a memberwise initializer, but > you’re right, this is a great feature. I love how this makes memberwise init > behavior a modifier on existing initializers.
I’d be inclined to drop the “()” on these, though. It appears to imply an empty parameter list is allowed, when it is not. >> Properties with initial values >> >> struct S { >> let s: String = "hello" >> let i: Int = 42 >> >> // user declares: >> memberwise init() {} >> // compiler synthesizes: >> init(s: String = "hello", i: Int = 42) { >> self.s = s >> self.i = i >> } >> } > In the case of let properties, I’m uncomfortable with this behavior and it > contradicts our current init rules (the synthesized code isn’t legal). > Please change the example to var properties, and then it’s can fit with the > model :-). > > That said, I think the interaction of explicit initializers and memberwise > initializers begs discussion. It would be a much simpler model to only get > memberwise parameters for properties without an explicit init. Have you > considered this model, what are the tradeoffs with allowing vars to overwrite > them? Allowing an explicit init to be overwritten by the memberwise > initializer seems potentially really confusing, and since you allow explicit > arguments on inits, this could always be handled manually if someone really > really wanted it. For example, they could write: > > memberwise init(s : String) { > self.s = s > } > > If they wanted to get the sugar of memberwise inits (presumably for other > properties without an explicit init) but still allow one to be overwritten. > > >> >> <https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md#partial-memberwise-initialization>Partial >> memberwise initialization >> >> struct S { >> let s: String >> let i: Int >> >> // user declares: >> memberwise init() { >> i = getTheValueForI() >> } >> // compiler synthesizes (suppressing memberwise initialization for >> properties assigned in the initializer body): >> init(s: String) { >> self.s = s >> // body of the user's initializer remains >> i = getTheValueForI() >> } >> } > This doesn’t seem like the right behavior to me. The compiler shouldn’t be > in the business of scanning the body of the init to decide what members are > explicitly initialized. I’d suggest that the model simply be that the > contents of the {} on a memberwise init get injected right after the > memberwise initializations that are done. This mirrors how properties with > default values work. > > >> >> <https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md#lazy-properties-and-incompatible-behaviors>lazy >> properties and incompatible behaviors >> >> struct S { >> let s: String >> lazy var i: Int = InitialValueForI() >> >> // user declares: >> memberwise init() { >> } >> // compiler synthesizes: >> init(s: String) { >> self.s = s >> // compiler does not synthesize initialization for i >> // because it contains a behavior that is incompatible with >> // memberwise initialization >> } >> } > Yes, this is likely to be subsumed into JoeG’s "behaviors” proposal. In the > meantime, I’d suggest no behavior change for lazy properties. > > >> >> <https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md#nomemberwise-properties>@nomemberwise >> properties >> >> struct S { >> let s: String >> @nomemberwise let i: Int >> >> // user declares: >> memberwise init(configuration: SomeTypeWithAnIntMember) { >> i = configuration.intMember >> } >> // compiler synthesizes: >> init(configuration: SomeTypeWithAnIntMember, s: String) { >> self.s = s >> i = configuration.intMember >> } >> } > @nomemberwise is an interesting extension, but since it is a pure extension > over the basic model, I’d suggest moving this into a “possible future > extensions” section. The proposal doesn’t need this feature to stand on its > own. > >> >> <https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md#delegating-and-convenience-initializers>delegating >> and convenience initializers >> >> struct S { >> let s: String = "hello" >> let i: Int = 42 >> >> // user declares: >> memberwise init() {} >> // compiler synthesizes: >> init(s: String = "hello", i: Int = 42) { >> self.s = s >> self.i = i >> } >> >> // user declares: >> memberwise init(describable: CustomStringConvertible) { >> self.init(s: describable.description) >> } >> // compiler synthesizes (adding forwarded memberwise parameters): >> init(describable: CustomStringConvertible, i: Int = 42) { >> self.init(s: describable.description, i: i) >> } >> } > This example is introducing two things: convenience inits, but also parameter > arguments. For the sake of the proposal, I’d suggest splitting the parameter > arguments out to its own discussion. It isn’t clear to me whether the > memberwise initializers should come before explicit arguments or after, and > it isn’t clear if we should require the developer to put something in the > code to indicate that they exist. For example, I could imagine a syntax like > this: > > memberwise init(…) {} > memberwise init(describable: CustomStringConvertible, ...) { > > Where the … serves as a reminder that the init takes a bunch of synthesized > arguments as well. > >> >> <https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md#subclass-initializers>subclass >> initializers >> >> class Base { >> let baseProperty: String >> >> // user declares: >> memberwise init() {} >> // compiler synthesizes: >> init(baseProperty: String) { >> self.baseProperty = baseProperty >> } >> } >> >> class Derived: Base { >> let derivedProperty: Int >> >> // user declares: >> memberwise init() {} >> // compiler synthesizes (adding forwarded memberwise parameters): >> init(baseProperty: String, derivedProperty: Int) { >> self.derivedProperry = derivedProperty >> super.init(baseProperty: baseProperty) >> } >> } > This also seems unclear to me. We’re generally very concerned about tightly > coupling derived classes to their bases (in an API evolution scenario, the > two classes may be in different modules owned by different clients). > Further, the base class may have multiple inits, and it wouldn’t be clear > which one to get the arguments from. > > >> >> <https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md#detailed-design>Detailed >> design >> >> >> <https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md#syntax-changes>Syntax >> changes >> >> This proposal introduces two new syntactic elements: the memberwise >> initializer declaration modifier and the @nomemberwise property attribute. >> > As before, I’d suggest splitting @nomemberwise out to a “potential future > extensions section”. > >> Algorithm >> >> The steps described in this section will be followed by the compiler when it >> performs memberwise initialization synthesis. These steps supercede the >> synthesis of initialization for properties with initial values that exists >> today. >> >> When the compiler performs memberwise initialization synthesis it will >> determine the set of properties that are eligible for synthesis that are not >> directly initialized in the body of the initializer. It will then synthesize >> parameters for them as well the initialization of them at the beginning of >> the initializer body. >> > I’d strongly suggest considering a model where properties that have an > explicit initializer don’t get a memberwise init. > > Have you considered whether computed properties make sense to loop into your > model? > > Typo "initialzier”. > >> >> >> <https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md#objective-c-class-import>Objective-C >> Class Import >> >> Objective-C frameworks are extremely important to (most) Swift developers. >> In order to provide the call-site advantages of flexible memberwise >> initialization to Swift code using Cocoa frameworks this proposal recommends >> introducing a MEMBERWISE attribute that can be applied to Objective-C >> properties and initializers. >> > This is also an orthogonal extension on top of the base proposal. I’d > suggest splitting it off to a “possible future extensions” section as well. > >> >> >> <https://github.com/anandabits/swift-evolution/blob/flexible-memberwise-initialization/proposals/NNNN-flexible-memberwise-initialization.md#impact-on-existing-code>Impact >> on existing code >> >> The changes described in this proposal are strictly additive and will have >> no impact on existing code. >> >> One possible breaking change which may be desirable to include alongside >> this proposed solution is to elimintate the existing memberwise initializer >> for structs and require developers to specifically opt-in to its synthesis >> by writing memberwise init() {}. A mechanical transformation is possible to >> generate this declaration automatically if the existing memberwise >> initializer is removed. >> > I think that that would be very interesting to discuss, but I lean towards > keeping our existing model for synthesizing a memberwise init if there is no > other init in a struct (and we should do it for classes as well). Requiring > someone to write "memberwise init() {}” is just boilerplate, and producing it > as “internal” avoids most of the problems from being something undesirable > being generated. That said, I see the argument that being more explicit is > good. > > Overall, I’m a huge fan of this proposal and the direction you’re going in. > > -Chris > > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution -Dave
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution