> On Dec 27, 2015, at 9:51 AM, Matthew Johnson via swift-evolution
> <[email protected]> wrote:
>
>>
>> On Dec 26, 2015, at 11:31 PM, Chris Lattner <[email protected]
>> <mailto:[email protected]>> wrote:
>>
>> On Dec 25, 2015, at 12:04 PM, Matthew Johnson <[email protected]
>> <mailto:[email protected]>> 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.
>
> Sounds good. I just submitted a PR. I think it’s ready. Please let me know
> if you feel any further changes are necessary.
>
>>
>>>> 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.
>
> I know changing the existing behavior would require very careful thinking. I
> am absolutely open to any solution that allow a default value for let
> properties to be specified whether it changes the existing behavior or not.
> What is the best way I can help to move this discussion forward in a
> productive manner? Would it be a good idea to start a new thread on the
> topic? Or is this something you feel like the core team needs to mull over
> for a while before we can have a productive conversation on the list?
At least for structs, there's almost no reason for the memberwise-initialized
properties to be `let`s, since preventing partial mutation of a value doesn't
put any effective limits on users of the type. If you have:
struct Foo {
let x
let y
memberwise init(...)
}
then even though you can't say:
var foo = Foo(x: 1, y: 1)
foo.x = 2
you can do the equivalent partial update by memberwise initialization:
var foo = Foo(x: 1, y: 1)
foo = Foo(x: 2, y: foo.y)
and it's highly likely both forms will be optimized to the same thing.
-Joe
>
>>
>>>> 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 :-)
>
> I agree with you on not holding back the base proposal.
>
> I really appreciate you noticing that this should really be orthogonal to the
> base proposal. I’ve already been giving this a lot of thought. It is very
> clear to me now that a much more general parameter / argument forwarding
> feature is the right approach. I am going to pursue a proposal for that as
> well.
>
>>
>>>> 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.
>
> Glad to hear breaking compatibility is ok in this case if it is required for
> consistency.
>
>>
>> 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 briefly addressed this in the alternatives considered section. I’ll fill
> that out with additional details including the points you raise.
>
> I feel pretty strongly that we should enforce the access control rules stated
> in the proposal. In addition to the Pros you note:
>
> 1. I think it is usually the right thing to do. If the caller can’t see a
> member it probably doesn’t make sense to allow them to initialize it.
>
> 2. If we expose more private-members by default then memberwise
> initialization is useless under the current proposal in many cases. There
> would be no way to prevent synthesis of parameters for more-private members.
> We have to choose between allowing callers to initialize our internal state
> or forgoing the benefit of memberwise initialization.
>
> 3. If a proposal for `@nomemberwise` is put forward and adopted that would
> allow us to prevent synthesis of parameters for members as desired.
> Unfortunately `@nomemberwise` would need to be used much more heavily than it
> otherwise would (i.e. to prevent synthesis of memberwise parameters for
> more-private members). It would be better if `@nomemberwise` was not
> necessary most of the time.
>
> 4. If callers must be able to provide memberwise arguments for more-private
> members directly it is still possible to allow that while taking advantage of
> memberwise initialization for same-or-less-private members. You just need to
> declare a `memberwise init` with explicitly declared parameters for the
> more-private members and initialize them manually in the body. Requiring the
> programmer to manually write any code that exposes more-private members is a
> arguably a very good thing.
>
> I think #4 above addresses the con you mention pretty well and #2 above is a
> significant drawback to not enforcing the access control rule (#3 is also
> pretty significant IMO).
>
> I’m sure this will be a point of discussion during review. I’m prepared to
> defend the decision I made but will also keep my mind open to opposing
> arguments.
>
>>
>> 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.
>
> Thanks!
>
>> 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.
>
> I’ll add a note to make this clear.
>
>>
>>
>>>> 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
>>
>
> _______________________________________________
> swift-evolution mailing list
> [email protected] <mailto:[email protected]>
> https://lists.swift.org/mailman/listinfo/swift-evolution
> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution