[swift-evolution] [Review] SE-0018 Flexible Memberwise Initialization

Matthew Johnson matthew at anandabits.com
Fri Jan 8 11:31:41 CST 2016


> On Jan 8, 2016, at 11:03 AM, Paul Cantrell via swift-evolution <swift-evolution at swift.org> wrote:
> 
> What is your evaluation of the proposal?
> 
> I have reservations about it. I think it should be deferred in search of a more generic solution, perhaps to be resurrected if the search for generality fails.
> 
> I appreciate the tremendous care that has obviously gone into the proposal. The dual attention to use cases and corner cases is admirable. The proposal present a thorough understanding of the problem that includes considerations I certainly hadn’t thought of!

Thanks Paul!

> 
> Still, I can’t shake unease about the proposed solution. As I read the examples, they’re not quite self-explanatory: a lot of magic, but the result doesn’t feel quite magical. Without being able to see what the compiler synthesizes, it’s often not obvious what will happen. As I read the detailed rules, they all sound quite sensible, but taken together feel like they’ll be hard to keep track of, and will lead to a lot of frustrated experimenting with the compiler. Tricky questions lurk all over. For example, what happens when I have a 7-member struct, all 7 parameters use memberwise initialization, but then I want to add some custom logic for the initialization of member 3? I think I have to either reorder the params or abandon … altogether? I feel like those tricky questions should melt away once I grasp the underlying principle, but there isn’t one to grasp; it’s just a bunch of tricky cases.
> 
> On reflection, it comes down to this: the feature to functionality ratio is too high.

Would you propose removing the current implicit memberwise initializer for structs on the same grounds?  This proposal effectively fleshes that feature out giving it more functionality.  The only fundamental complexity it adds is the access control rules, which I feel are pretty important to enforce.


> 
> That probably requires some explanation. By “feature,” I mean a specific behavior the software implements for which users will need a mental model. By “functionality,” I mean the set of things one can do with the software, and more importantly the nature of the user’s experience doing them.
> 
> An example of a high feature/functionality payoff is Swift’s as-if-immutable structs. There’s a fairly large set of relevant features: the let/var distinction for declarations, the “mutating” keyword, the interaction of “let” with setters and mutating methods, and the way “let” recursively affects structs inside of structs. However, all of that folds into a mental model with a nice unifying principle: Swift structs behave semantically as if they are all always immutable and mutations create a new struct and reassign it to the variable; however, they perform better than that, because the compiler will optimize that into a direct mutation when possible. The features pay huge functionality dividends across a wide variety of situations: defensive programming, passing data across threads, isolating responsibility … it goes on.
> 
> (Really, “functionality” is a qualitative thing, more about the experience than just “what can I do,” and so talking about the “feature to functionality ratio” is only a metaphorical gesture. It captures the right feeling, though.)
> 
> In this proposal, there’s a similarly large set of new features: the “memberwise” keyword, the new use of …, multiple interacting rules about memberwise property eligibility, synthesized initialization, rules about how that interacts with manual initialization. For all that, though, the functionality gain is limited: we shed some senseless repetition — that’s good! — but only for copying of parameters to properties, only when they’re in the same order, and only in initializers.
> 
> The proposal reads like a set of specific use cases translated directly into specific features, without a good eye to the bigger picture.
> 
> It feels to me like this functionality should come from a feature set that is more general, more arbitrarily composable, and pays greater dividends in a wider variety of situations. As a simple example, what if I want to write an updateFrom(other: Self) method that does a mass copy of all properties? Why doesn’t this proposal help with that, too? Because the … placeholder and the synthesized copying are tightly coupled (1) to each other and (2) to initialization.
> 
> I’m not sure what the better answer is, but it’s out there. I didn’t follow the whole discussion, but I did notice Joe Groff’s proposal for a Members tuple; that seems to me to be getting much warmer. I’d much prefer something along those lines, even if it were slightly more verbose.

I think the direction suggested by Joe (and Dave) is interesting.  But they haven’t explained how it would handle some important use cases this proposal addresses (default parameter values, subset of members without using a struct, etc).  If we are going to reject this proposal in hope of a more general solution I would at least like to see a path forward that might be able to address these use cases.

More importantly, the general features on their own would not address the problems addressed by this proposal.  There would still need to be initializer-specific magic.  Joe hinted at what that might be but has not fleshed out all the details yet.  Maybe it would be a simpler model but we would need to see more specific details.

I don’t believe a fully generalized solution is possible.  There are a lot of initialization-specific constraints that must be met (definitive initialization, single initialization of `let` properties, etc).

> 
> (Aside, a small nitpick, but it really bugs me: initialization has O(M+N) complexity, not O(M×N) complexity. One doesn’t initialize every member with every parameter.)

MxN is members x initializers.

> 
> 
> Is the problem being addressed significant enough to warrant a change to Swift?
> 
> It’s certainly worth considering. Mindless parameter copying is a source of low-value verbosity, and can lead to errors.
> 
> 
> Does this proposal fit well with the feel and direction of Swift?
> 
> It does in that it aims to reduce developer error and verbosity by providing an idiom to solve a common problem.
> 
> It does not in that the idiom is so narrow. The language is moving away from that in other realms (e.g. lazy).
> 
> 
> If you have you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
> 
> I’ve never heard of a language with such a high specialized tool for doing just this.
> 
> Ruby and Javascript allow programmatic traversal of both arguments and properties, and provide enough reflection to automate that. Developers in both languages do write ad hoc solutions to do almost exactly what this proposal does, though they’re not widely used. The most common is probably variations on this:
> 
> def initialize(**args)
>   args.each do |prop, value|
>     obj.send("#{prop}=", value)
>   end
> end
> 
> …which uses key/value pairs from an argument array to set properties.
> 
> Being able to convert arguments to a dictionary is something Swift certainly might investigate.

We should have a safe solution that allows the compiler to enforce type checking and definitive initialization rules.

> 
> 
> How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
> 
> I read the proposal carefully, but only lightly skimmed the discussion and other reviews.
> 
> Cheers,
> 
> Paul
> 
> 
>> On Jan 6, 2016, at 4:47 PM, Chris Lattner via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>> Hello Swift community,
>> 
>> The review of "Flexible Memberwise Initialization" begins now and runs through January 10th. The proposal is available here:
>> 
>> 	https://github.com/apple/swift-evolution/blob/master/proposals/0018-flexible-memberwise-initialization.md <https://github.com/apple/swift-evolution/blob/master/proposals/0018-flexible-memberwise-initialization.md>
>> 
>> Reviews are an important part of the Swift evolution process. All reviews should be sent to the swift-evolution mailing list at
>> 
>> 	https://lists.swift.org/mailman/listinfo/swift-evolution
>> 
>> or, if you would like to keep your feedback private, directly to the review manager.
>> 
>> What goes into a review?
>> 
>> The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. When writing your review, here are some questions you might want to answer in your review:
>> 
>> 	* What is your evaluation of the proposal?
>> 	* Is the problem being addressed significant enough to warrant a change to Swift?
>> 	* Does this proposal fit well with the feel and direction of Swift?
>> 	* If you have you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
>> 	* How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
>> 
>> More information about the Swift evolution process is available at
>> 
>> 	https://github.com/apple/swift-evolution/blob/master/process.md
>> 
>> Thank you,
>> 
>> -Chris
>> Review Manager
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160108/36e4a17c/attachment.html>


More information about the swift-evolution mailing list