[Review] SE-0018 Flexible Memberwise Initialization


(Chris Lattner) #1

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

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


(Alex Johnson) #2

(this is mostly a repost of a message I sent to the "[draft]" thread for
this proposal, with some light editing to better match terminology in the
proposal)

*What is your evaluation of the proposal?*

I like this proposal. I think it will bring some much-needed ease-of-use.

I have reservations about the "..." placeholder for the memberwise
initialization parameters, though. I know this was suggested by
Chris Lattner, so I'm inclined to defer to his judgement. But, here are my
thoughts:

First, it's very close to the varags syntax (e.g. "Int...") which can also
appear in initializer parameter lists.

Second, and I think more important, I'm not sure that it's all that *useful*.
It's presence isn't necessary for triggering memberwise initialization
synthesis; that is already done by the "memberwise" keyword.

The primary example given in the proposal is:

memberwise init(anInt: Int, anotherInt: Int, ...) {

  /* code using anInt and anotherInt */

}

That is, it's used to indicate where the synthesized parameters appear in
the parameter list if there are also custom (non-memberwise) parameters.

My question is, *could the memberwise initialization parameters always be
last?* That would eliminate the need for the placeholder.

I don't think I've seen a compelling case for embedding the "..." *within*
a list of custom arguments, like:

memberwise init(anInt: Int, ..., anotherInt: Int) {
  /* code using anInt and anotherInt */
}

It's been mentioned several times in the discussion of this proposal that
this behavior is purely optional. If it turns out that there are rare cases
where placing the memberwise params in the middle is useful, authors can
use manual initialization.

···

On Wed, Jan 6, 2016 at 2:47 PM, Chris Lattner via swift-evolution < swift-evolution@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

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--

*Alex Johnson | Engineering Lead*

*Quick Left, Inc. <https://quickleft.com/>*
*Boulder **|* *Denver* *|* *Portland** |** San Francisco*

1 (844) QL-NERDS

@nonsensery

<https://github.com/quickleft> <https://www.facebook.com/quickleft>
<https://twitter.com/quickleft> <https://instagram.com/quick_left/>
<https://www.flickr.com/photos/quickleft> <https://vimeo.com/quickleft>

*What's it like to work with us? **TrainingPeaks, iTriage, and Ping
Identity share their stories in this short video** A Client's View
<https://vimeo.com/92286352>*.


(Paul Ossenbruggen) #3

* What is your evaluation of the proposal?

I think it will greatly help out in more cases where it was not able to do so and will give you more control over it. One concern is that it may make the language more complex, now users need to know what the “memberwise” keyword means, fortunately it will be easily searched.

  * Is the problem being addressed significant enough to warrant a change to Swift?

Yes.
  * Does this proposal fit well with the feel and direction of Swift?
Yes
  * If you have you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
Not Applicable.

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Read proposal and followed some of the discussion but not all.


(Dave Abrahams) #4

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

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?

It’s okay.

  * Is the problem being addressed significant enough to warrant a change to Swift?

I’m lukewarm about that. I have never found writing out the initializers I want to be a significant burden, and I find my code is better when they’re explicit. Every new feature increases the language's complexity and surface area, and I fear this one is not going to pay its way.

  * Does this proposal fit well with the feel and direction of Swift?

Yes, but I worry that it may be too early to add it. Other features in this space, like truly generic variadics, may well obsolete anything we do today. I’m not sure we should be designing convenience features that are likely to overlap with more general features coming down the road unless the inconvenience is very painful… which I personally don’t find it to be.

  * If you have you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

The proposal is more elegant than how you’d do this in Python, but on the other hand the mechanisms you’d use in Python are not single-purpose language features directed at memberwise initialization; they definitely pay their way because they can be used for much more.

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

A glance, admittedly.

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

-Dave

···

On Jan 6, 2016, at 2:47 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:


(David Owens II) #5

-1 for me.

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

  * What is your evaluation of the proposal?

I’m unconvinced that the value is warranted for the complexity that is being brought to the table. Couple this with the fact that it’s very easy to accidentally make breaking changes by simply re-ordering your members, adding new ones, or even assigning a default value. I just find it far too fragile.

  * Is the problem being addressed significant enough to warrant a change to Swift?

I don’t think so.

  * Does this proposal fit well with the feel and direction of Swift?

I suppose. However, it has a lot of impact on the resiliency of APIs, so I’d want to delay this feature until those issues are worked out first. The other concern is there is a lot of magic involved, especially when some of the future enhancements are looked at.

  * 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 used tools to do this in past, such as MACROs or snippet-like items. Those seemed to be more useful and less constrained. Also, I make use of Swift’s implicit initializers for structs for internal code. While that is nice, I’ve not been convinced that moving this functionality to public is a good thing.

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I’ve been following the iterations and partaking in some of the conversations.

-David

···

On Jan 6, 2016, at 2:47 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:


(Brent Royal-Gordon) #6

  * What is your evaluation of the proposal?

I am generally in favor. I enjoy the current memberwise initializer feature and would like to see it become useful in more cases.

One thing I don't like (and was intending to discuss—the review snuck up on me) is the keyword `memberwise`. This is the name of the current feature, but I don't think it's very well-chosen. "Member" refers to all of the things attached to a type: properties, subscripts, methods, initializers, etc. But a "memberwise" initializer only initializes the stored properties, not any of these other things. Perhaps instead of `memberwise`, the keyword should be `property` or `propertywise`.

I'm not precisely sure what would be best, and keyword bikeshedding might be best left for a separate proposal. In any case, this defect is not nearly severe enough to make me want to scuttle the feature.

  * Is the problem being addressed significant enough to warrant a change to Swift?

Yes. The current memberwise initializers are unavailable in any situation with even the slightest complications. I think this proposal vastly improves the feature.

  * Does this proposal fit well with the feel and direction of Swift?

I think it does. It makes something that was previously implicit explicit instead, reducing boilerplate while still providing plenty of flexibility.

  * If you have you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

I haven't, unless you count highly dynamic languages where you can easily build a constructor that initializes from a dictionary. This proposal is *far* more explicit than that sort of solution, which seems like an improvement to me.

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I've participated in discussions about this feature since before it was formally proposed; I think I may have been the first person to bring up memberwise initializers as a target for improvement on this list. I've dug around in the Swift compiler and took a vague stab at implementing some related features, although I didn't get very far. I think my understanding of this issue is pretty in-depth.

···

--
Brent Royal-Gordon
Architechies


(Lily Ballard) #7

  * What is your evaluation of the proposal?

+1 to the basic proposal. I'm much more reserved about the "Future enhancements"; some I don't want at all, some sound plausible but probably need changes.

Also, a question and a concern about the basic proposal. The question: you state that the only impact this has on existing code is structs with private properties that have been getting an implicit internal memberwise initializer will have the initializer be private. That's fine, but assuming that the implicit memberwise initializer behaves identically to `memberwise init(...) {}`, surely this proposal also makes the implicit memberwise initializer gain defaulted arguments for any var properties with an initializer expression? Don't get me wrong, I think it's good to change that, but it should be explicitly noted.

As for my concern, it's with the following rule:

If the initializer body assigns to a var property that received memberwise initialization synthesis report a warning. It is unlikely that overwriting the value provided by the caller is the desired behavior.

I understand why you put this in there, but this is a warning that cannot be suppressed and will make it impossible to use a memberwise initializer for perfectly legitimate cases where you do in fact want to mutate the property after it's been assigned to.

What might be a reasonable thing is a warning that occurs if you assign to the var property without ever having read from it (i.e. a dead store warning on the memberwise initialization of the property). That way if I mutate a property to contain a derived value it's fine, but if I simply write to it without ever reading it, it's a problem.

  * Is the problem being addressed significant enough to warrant a change to Swift?

I think so. Writing initializers can be a large source of boilerplate in Swift, especially when using classes where you can't get the implicit memberwise initializer.

  * Does this proposal fit well with the feel and direction of Swift?

Yes.

  * If you have you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

I'm not aware of a similar feature in any language I'm familiar with.

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I spent a few minutes reading over the whole proposal. I did not read any of the swift-evolution thread.

-Kevin Ballard


(plx) #8

I like the general notion of something along these lines but admittedly haven’t had time to dig into the proposal specifics yet.

I have some concerns about cross-interactions with other features that are either also under discussion or are at least very anticipatable.

First, I know there has already been some discussion of allowing definition of stored fields in (some) extensions (e.g., something like allowing definition of stored fields in extensions within the module that defines the type).

E.G., something like this may become possible (assume all files are compiled together):

    // in `ComplicatedClass.swift`
    class ComplicatedClass {
      let text: String
      
      // how will this get expanded,
      // given the extensions below?
      memberwise init(...)
    }
    
    // in `ComplicatedClass+Foo.swift`
    extension ComplicatedClass {
      var fooData: Foo? = nil
      // presumably stuff-involving-`fooData`
    }
    
    // in `ComplicatedClass+Bar.swift`
    extension ComplicatedClass {
      var barData: Bar = Bar.standardBar
      // presumably stuff-involving-`barData`
    }

It doesn't seem impossible to specify how the memberwise-initialization would interact with constructs like the above, but I'd worry a bit about it making a feature that's already looking *rather* complicated even more so.

Especially since, if I had to pick just one, I'd think the ability to define stored properties outside the initial definition is a bigger win than a nice memberwise-initialization construct, even though both seem handy.

Secondly, I’m a bit unsure how this will interact with e.g. the property-behavior proposal if both wind up ratified. For `lazy`, the interaction with `memberwise` is easy — it is omitted from the list — but when you get into e.g. something like a hypothetical `logged` or `synchronized` or `atomic` — wherein there is custom behavior, but the field would still need initialization — you’d want them to be included in the `memberwise` init.

It’s a bit unfair to bring up another proposal, but this proposal and something like the property-behavior proposal *would* need to work well together (if both are approved).

Thirdly, I’m not sure what the current plans are (if any) for users to be able to specify the precise memory-layout of a struct; apologies if this is already a feature, I simply haven’t looked into it.

**Today**: I order stored-field declarations for ease-of-reading (e.g. grouped into logical groups, and organized for ease-of-reading).

**Under Proposal**: I sometimes will get to choose between the “ease-of-reading” declaration ordering and the “cleanest-reading memberwise init” declaration ordering. These may not always be identical.

**Future?**: I may have to choose between the “ease-of-reading” declaration ordering, the “cleanest-reading member wise init” declaration ordering, and (perhaps?) the “intended memory-layout” declaration ordering.

I don’t want to make this proposal more-complicated than it already is, but I worry a bit about having too many things impacting the choice of how to order declarations in source files; it may be better to include a way to explicitly declare the ordering-for-memberwise:

E.G., some way of explicitly indicating the memberwise ordering, perhaps like this:

    // syntax example re-using `ComplicatedClass`
    class ComplicatedClass {
      @memberwise($parameterList)
      // ^ can use just @memberwise to get default ordering + the defaults from
      // the property declarations, but perhaps require the explicit listing
      // whenver the ordering is not well-defined (e.g. if you have properties
      // declared in extensions…then you need to order it yourself)
      //
      // @memberwise(text="Example",barData=,fooData)
      // - `text="Example"` => memberwise init has text="Example"
      // - `barData=` => memberwise init has `barData` w/out default
      // - `fooData` => memberwise init has `fooData` w/default if it has one
      //
      // …and e.g. the above would make:
      //
      // memberwise init(...)
      //
      // ...expand-to:
      //
      // init(text:String = "Example", barData: Bar, fooData:Foo?=nil)
      //
      // ...and with the @memberwise declaration supporting a `...` for `super`
      // placement, like so:
      //
      // // superclass members come before:
      // @memberwise(...,)
      // @memberwise(...,$parameterList)
      //
      // // superclass members come after
      // @memberwise(,...)
      // @memberwise($parameterList,...)
      //
      // ...perhaps with tweaked syntax (`@memberwise(...,$)` or `@memberwise(...,self)`)
      // to be bit easier to read when you don't have an explicit parameter list?
    }

...which of course potentially only-further complicates the feature in some ways, but avoids having this use of this feature *necessarily* impact how one might choose to order declarations?

···

On Jan 6, 2016, at 4:47 PM, Chris Lattner via swift-evolution <swift-evolution@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

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Tino) #9

  * What is your evaluation of the proposal?

-1
It adds a lot of stuff to the language that doesn't pay off enough.
There are already many concepts that are very specific and useful only for init, and it should be avoided to add more.

  * Is the problem being addressed significant enough to warrant a change to Swift?

Definitely yes, but the imho most important thing (initial values for constants) will require even more additional syntax, as it isn't covered yet.

  * Does this proposal fit well with the feel and direction of Swift?

You will know better, but hope for bigger ambitions :wink:

  * If you have you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

That is the source of my major objection:
The proposal is ok, but it makes initialization even more complicated — for me, this would destroy the last advantage Swift has over other languages (Scala, Kotlin...) in this area.
Other approaches are imho superior in every single aspect, and even if they are not "swifty" enough to get incorporated, their performance should be our reference value.

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Quite a lot, as I've been involved in the discussion.

Tino


(Joe Groff) #10

The proposal says that "let" properties with inline initializers should be left out of the memberwise initialization, AIUI on the grounds that a manually-written initializer would not be allowed to override the inline initialization:

class C {
  let x = 1738
  init(x: Int = 679) {
    self.x = x // Error, self.x already initialized
  }
}

However, this is also true for vars. Semantically, if you change 'x' to a var in the above example, you get an initialization followed by an assignment:

class C {
  let x = dump(1738)
  init(x: Int = dump(679)) {
    self.x = x
  }
}

      C() // dumps 1738, then 679

which, if the initialization has side effects, will likely be surprising. We could say that the memberwise initializer elides the inline initialization of `var`s, on the grounds that initializations ought not to have side effects, but then we're introducing a behavior change in inline initializers for `var`s in the face of `memberwise` initializers that also cannot be replicated by a manually-written initializer. If we make that behavior change for vars, I think it's reasonable, and more orthogonal, to extend the same grace to lets as well. That also simplifies the rules for what appears in the memberwise initializer—there's now only two rules (or one, if we also remove the access control filter, as I've suggested in another subthread).

-Joe


(Paul Cantrell) #11

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!

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.

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.

(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.)

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.

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@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

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Lily Ballard) #12

I had another thought last night about this proposal. Since it appears to be working as syntactic sugar, if I write something like

var x: Int
memberwise init(...) {
    // what does x refer to here?
}

Inside of the memberwise init, does the bare identifier `x` refer to the property, or to the implicit parameter? I think it should refer to the property, because making it refer to the implicit parameter means you'd be referring to a variable that was never visibly declared anywhere. AFAIK the only precedent for that is the implicit argument `newValue` to setters, `oldValue` to didSet observers, and `error` to catch blocks, but those are all constant identifiers that mean the same thing in every such context, as opposed to memberwise init where the implicit parameters are different for each init. More generally, we should avoid exposing such non-declared variables without a compelling reason.

The other argument in favor of making `x` refer to the property is because that's just generally more useful. All the properties match the values of the parameters on the first line of the user-supplied body to the memberwise init, so there's no benefit to be had from leaving the parameters accessible to user code.

As for how to actually accomplish this, assuming this feature is implemented as an AST transformation, ideally we'd have some way to synthesize identifiers in the AST that cannot possibly be referenced by user code (e.g. some form of identifier namespacing if it exists, or some form of gensym-like behavior). Alternatively, if there's no particularly good way to do this, we could just use something like `__name` as the internal parameter name.

-Kevin Ballard


(Jordan Rose) #13

Hi, Matthew. (Hi, everyone.) Thanks for putting together a detailed and well-thought-out proposal. I had some smaller comments:

- Given that these initializers are based on access control, is "public memberwise init(...)" different from "internal memberwise init(...)"? Can I put both in the same type?

- Why not just put the "memberwise" in the parameter list, and drop the decl modifier? This came up in the draft discussion but I didn't see any follow-up.

- I kind of agree now that "memberwise" is the wrong name, but I don't have a better one.

…but after reading through the formal review discussion, I have to say I don't think this is a good feature for Swift. I tend to agree with David Owens and others that this is too much magic in one keyword. (I picked David because I think his responses most closely match my concerns out of the dissenters.)

Imagine trying to explain this feature in The Swift Programming Language. It starts off very simple with the perfect use case:

public struct Point {
  public var x: Double
  public var y: Double
  public memberwise init(...) {}
}

…but then spends the rest of the chapter going over everything in the proposal: why you can't provide a default for 'let' properties, why hiding a setter affects the presence of a member, and what to do if you want to change it but preserve backwards binary compatibility. It seems like a big, complicated feature that "does what you mean" only when it's first added and then becomes an impediment to any later change.

I'm motivated to solve the tiny value struct case, the public C-like struct case, but I don't think I want this creeping into the interface of a public class. I'd rather go with the "annotation on parameters" solution (which would be a separate proposal, of course).

public struct Point {
  public var x: Double
  public var y: Double
  public init(self x: Double, self y: Double) {}
}

or

  public init(@assigned x: Double, @assigned y: Double) {}
  public init(self.x: Double, self.y: Double) {}
  // something else

For comparison with other languages, the "memberwise initializer" proposal is closest to C's brace-initialization, but C structs aren't resilient to change in the way that classes are, and they won't break if you reorder the members, while this will. The "annotation on parameters" idea is precedented in CoffeeScript, but I don't know of any other languages that do it.

This proposal is very practical and covers many common use cases, but I just don't see it as naturally fitting into the language.

Best,
Jordan

···

On Jan 6, 2016, at 14:47, Chris Lattner via swift-evolution <swift-evolution@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

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Angelo Villegas) #14

- What is your evaluation of the proposal?

I’m in favour of this proposal. I really like the first syntax of @default from the future enhancements.

- Is the problem being addressed significant enough to warrant a change to Swift?

Yes.

- Does this proposal fit well with the feel and direction of Swift?

It feels like it.

- How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I have read the proposal and followed some of the discussions.

···

On 7Jan, 2016, at 6:47 AM, Chris Lattner via swift-evolution <swift-evolution@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

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Patrick Gili) #15

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

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?

Overall, I think the proposal has merit. However, I have some concerns around two areas:

1) It adds complexity to initializers, which already have a fair amount of complexity around them.

2) I don't see anything in the proposal that indicates how a developer can see what the compiler synthesizes. As mentioned above, initializers are already complex, and having this capability would greatly help in troubleshooting problems when designing types.

  * Is the problem being addressed significant enough to warrant a change to Swift?

Yes.

  * Does this proposal fit well with the feel and direction of Swift?

I'm ambivalent about this. I had genuinely good feelings about Swift from the time Apple introduced it at WWDC '14. It provided software developers with many conveniences and removed a lot of complexity from its predecessor, Objective C. Sometimes flexibility adds complexity, and on some level I feel like this proposal adds some flexibility. While the proposal definitely solves a problem, it comes at a cost. Thus, we have to ask ourselves if the benefit outweighs the cost. At first glance, I think it does.

  * If you have you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

I have not used any programming languages that synthesize sophisticated initializers. Most languages provide generate an automatic initializer that does nothing, which often leads to more problems than it is worth.

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I thorough read the proposal three times, compared it to other languages that use on a regular basis, and gave it some serious thought.

···

On Jan 6, 2016, at 5:47 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Howard Lovatt) #16

* What is your evaluation of the proposal?

I like the general direction of more flexible property-wise initialisation however I do have some reservations about the detailed proposal, in particular:

1. You can’t initialise lets.
2. You can’t initialise more-private-stored properties than the property-wise initialiser itself.
3. You can't label property-wise initialiser arguments.
4. It is not totally clear which properties are to be initialised property-wise.
5. The proposal adds to the existing menberwise initialisers and the default initialisers; which then means there are 4 initialisers (manual, current memberwise default, and new memberwise), therefore I would prefer a proposal that encompassed all of these.
6. Super types need a default initialiser.
7. The memberwise init does not have default values for its memberwise arguments which means that all memberwise arguments need to be specified when calling the memberwise init (like current memberwise init).
8. Stored properties have to be given a default value to participate in memberwise initialisation.
9. `memberwise` isn’t a great keyword, since funcs are also members
10. The … notation can be a bit invisible.

However I think that if the design space is opened up then these issues could be addressed. Here is a modification to the existing proposal:

1. Basic example: demonstrates a short form for C-like structs and let initialisation:

    // Short-property-wise form
    class Size2D properties { // Note: properties keyword
        let width = 0.0, height = 0.0 // Note: let
    }

    // Translation to long-property-wise form
    class Size2D {
        properties { // Note: obvious which properties are property-wise initialised
            let width = 0.0, height = 0.0
        } init(properties) {} // Note: placeholder, properties, for property-wise args and no init body
    }
    
    // Translation to basic Swift
    class Size2D {
        let width: Double
        let height: Double
        init(width: Double = 0.0, height: Double = 0.0) { // Note: default values for property-wise args
            self.width = width
            self.height = height
        }
    }

2. Example of how super is to be called.

    // Short-property-wise form
    class Size3D: Size2D properties(width: Double = 0.0, height: Double = 0.0) {
        let depth: Double = 0.0
    }

    // Translation to long-property-wise form
    class Size3D: Size2D {
        properties(width: Double = 0.0, height: Double = 0.0) {
            let depth: Double = 0.0
        } init(properties) {}
    }
    
    // Translation to basic Swift
    class Size3D: Size2D {
        let depth: Double
        init(width: Double = 0.0, height: Double = 0.0, depth: Double = 0.0) { // Note: super args before property-wise args
            self.depth = depth
            super.init(width: width, height: height)
        }
    }

3. More involved example with private property, properties arg label, other init, and other methods

    // Only long-property-wise form allowed since other methods and other initialisers required
    class LoggedAndScaledSize2D: Size2D {
        properties(width: Double = 0.0, height: Double = 0.0) {
            private var times scale: Double = 0.0 // Note: label, times, and private
        } init(properties) {}
        properties init(properties, logger: Logger? = nil) { // Note: only 1 property-wise init can have properties and super args
            logger?.log(self) // Note: rest of init
        }
        var scaledWidth: Double { // Note: other methods
            get { return scale * width }
    }

    // Translation to basic Swift
    class LoggedAndScaledSize2D: Size2D {
        private var scale: Double // Note: private
        init(width: Double = 0.0, height: Double = 0.0, times scale: Double = 0.0) { // Note: label times
            self.scale = scale
            super.init(width: width, height: height)
        }
        init(width: Double = 0.0, height: Double = 0.0, times scale: Double = 0.0, logger: Logger? = nil) {
            self.scale = scale
            super.init(width: width, height: height)
            logger?.log(self) // Rest of init
        }
        var scaledWidth: Double { // Other methods
            get { return scale * width }
            set { scale = newValue / width }
        }
        var scaledHeight: Double {
            get { return scale * height }
            set { scale = newValue / height }
        }
    }

4. The existing memberwise and default initialisers are deprecated.

Obviously the above is just a three examples - happy to flesh out details if there is interest.

The semantics of the proposal are as though the literal translations from short-property-wise form, to long-property-wise form, to basic Swift occurred.

The proposed semantics "as though literal translated" and previous compiler-written initialisers deprecated means that `struct Length { var length: Double = 0.0 }` is now an error - it has no initialisers. Programmer would write `struct Length properties { var length: Double = 0.0 }`, note added properties keyword.

Whether properties is much better than memberwise and … is open to some debate!

        * Is the problem being addressed significant enough to warrant a change to Swift?

I think a revised proposal would be viable, but marginal as it stands.

        * Does this proposal fit well with the feel and direction of Swift?

In some ways yes (because Swift has compiler written initialisation already), but in others, like adding another way of doing initialisation, no (because one aim of the evolution is not to become a ‘kitchen-sink' language like C++).

        * If you have you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Yes I have used a similar feature in Scala and the current proposal is much more complicated. The Scala solution seems better to me. But see proposed alternative above.

        * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I have kept up with the discussions and have interacted with Matthew Johnston and others on this topic. I have also discussed with Bill Venners from Escalate; who is well known as an educator in the Scala community, the Scala version it is well liked in the Scala community and is easy to teach.

Glad this topic is under discussion,

-- Howard.

···

On 7 January 2016 at 09:47, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
Hello Swift community,

The review of "Flexible property-wise Initialization" begins now and runs through January 10th. The proposal is available here:

        https://github.com/apple/swift-evolution/blob/master/proposals/0018-flexible-property-wise-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@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

--
  -- Howard.


(Michel Fortin) #17

* What is your evaluation of the proposal?

At first glance it looks like it should be a simple thing, but a closer look lead me to believe it's conflating two things:

1. stored properties initialization
2. user-visible property values

Stored properties are the internal state, while user-visible properties is the exposed state. Initialization is about setting the internal state. While it's common to have initializers accept values as arguments, in the general case the initializer has to convert them from the external representation to the internal representation while setting the internal state.

For a plain type with only raw stored properties, internal state and exposed state are the same thing, and this proposal is simple and very appealing.

But for more complex types where the internal state does not map one-on-one to the exposed state, the proposal seems suboptimal. What you really want is to call all the publicly available setters, not set the raw values. But that goes against how things work in an initializer, where setters are skipped and the raw values are set directly.

I understand the proposal is trying to work around this problem by inferring things from the visibility attributes, but the rules seems complex, bug prone (because it bypasses the setters), the feature seems incomplete (missing computed properties), and in the end unnecessary (because you can use the setters). I think we'd be better served if there was simply a way to set properties in batch after initialization, perhaps like this:

  var object = MyObject()
  object .= (property1: 1, property2: "a")

(Note: you can *almost* implement this already through reflection and a custom operator taking a tuple.)

* Is the problem being addressed significant enough to warrant a change to Swift?

This proposal is a good way to get back the default memberwise initializer that structs with no initializer get for free, and allow it for classes when it makes sense. It'd be nice to have that.

I'm also of the opinion that it's worth addressing the verbosity of setting multiple properties at once. But for complex types that hide their internal state, I don't think the added complexity for determining the parameter list and the default values is worth it.

Also, I see no reason why a type should have to opt-in (by providing a memberwise initializer) so its users have a convenient way to set properties: it'd be much better to have a general solution that works everywhere.

* Does this proposal fit well with the feel and direction of Swift?

Not sure.

* If you have you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

I'm not aware of any.

* How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I read the proposal, and a lot of what was discussed on the list (but not everything).

···

--
Michel Fortin
https://michelf.ca


(Matthew Johnson) #18

As the review of the Flexible Memberwise Initialization proposal draws to a close I would like to offer some final thoughts.

First, I would like to thank everyone who has reviewed the proposal and participated in the discussion. You have all given me a lot to think about. I believe this discussion has been very productive. It has helped to move my thinking on the topic forward and shape a more complete, more compelling vision of where we can go.

At a high level I think there are a few takeaways.

First, there seems to be very broad (but not universal) agreement that something should be done to make trivial initialization code more concise. The problem is worth solving.

Second, there is more support than opposition for this proposal, but the response is definitely mixed. By my tally the responses are roughly:

55% favorable (Chris and I are both still favorable)
20% mixed
25% opposed

The categorization is somewhat subjective but I believe anyone who does a tally on their own will come up with reasonably similar results.

Third, there are some common and valid criticisms which are addressed further down below.

Finally, I after much vetting I still believe this proposal does a good job of fulfilling the goal it set out to do, namely improve the existing memberwise intializer by making it much more flexible.

Even several of those who oppose the proposal have agreed with that. The basis of their opposition is that once you work out the details of doing so the resulting complexity is not worth it.

Personally, I believe the increase in complexity over the current implicit memberwise initializer is not as significant as some perceive and the additional flexibility more than pays for the cost of the incremental complexity. The changes from current state can be summarized concisely as:

1. Allow the memberwise initializer to be used in classes
2. Allow default parameter values for `var` properties
3. Fix the problem the current memberwise initializer has with lazy properties
4. Use the `set` rather than `get` visibility for `var` properties
5. Allow you to request the memberwise initializer, including:
  i. Add additional parameters
  ii. include an initializer body
  iii. Specify access level, which will result in omission of memberwise parameters for more-private properties (it would be reasonable to limit this to private and internal if concerns about allowing it to be public are a significant factor)

The perceived complexity of this proposal focuses on the property eligibility rules. As noted in the list above, there are only two differences in those rules under the curernt proposal compared to the existing implicit memberwise initializer: #4 and #5.iii. In exchange for accepting those two changes this proposal gives us the increased functionality in the rest of the list.

Despite the proposal doing a good job of fulfilling the basic goal, there have been some very valid critiques of it:

1. **Complexity:** the rules of any workable automatic model are inherently nontrivial.
2. **Limitations:** it isn't possible to specify an explicit list of parameters, their order, their external lablels, and default values for `let` properties.
3. **Specificity:** the memberwise initialization is a very special case feature. It would be better to have more general facilities that support the memberwise initialization use case.

I have been giving a lot of thought to all of them. I espicially want to thank Dave Abrahams and Joe Groff for starting the discussion around looking for more general facilities to support memberwise initialization.

Ultimately, improving the existing memberwise initializer is not the best premise for a long-term solution to address the limitations of this proposal. A solution built on more general features can be just as clear and expressive, while also serving use cases beyond memberwise initialization.

With all of the above in mind, my recommendation is to accept this proposal and simultaneously keep working on more general facilities that can supercede the faciilities of this proposal (aside from the imiplicit memberwise initializer). I make this recommendation for the following reasons:

1. This proposal improves the implicit memberwise initializer which will not be touched by proposals for more general features adressing.
2. There is no guarantee that more general features addressing memberwise initialization will make it into Swift 3. Accepting this proposal guarantees we will see improvements that I believe are worthwhile, even if they are not a final solution.
3. Implementation could begin with an eye on the more general approach, possibly providing a head start on implementing them.

I would also like to begin discussion regarding three general facilities that can work together to improve the conciseness and expressiveness of our initializers. The combination of the first two facilities can supercede the functionality of this proposal. I believe all three facilities working together can signficantly increase the clarity and expressiveness of our initialization code.

1. Parameter forwarding: I began working on a general purpose parameter forwarding proposal prior to this review. This feature will add clarity to various forms of chained initializers. It will also be to any function that needs to forward a set of arguments from its caller directly to another function, not just to initializers.

2. Partial initializers: The idea for this proposal was inspired by thinking about Joe's example of a more general solution. Using a setter to perform initialization (especially of `let` properties) just seems wrong to me. What we need is a partial initializer which can be used to factor out common initialization logic. Partial initialzers are a general purpose initialization tool, not a tool specific to memberwise initializers. However, when combined with parameter forwarding and a few implicit partial initializers, it is possible to replace the explicit memberwise initializers described in this proposal with syntax that is just as concise.

3. Property lists: Property lists were inspired by two subthreads of this review. One was Joe's idea for a computed "members" tuple property. The other is all of the discussions related to limitations and lack of control in the Flexible Memberwise Initialization proposal. Property lists are a declaration that allows a user to declare a specific set of properties, in a specific order, with specific labels and specific default parameter values. This declaration results in a synthesized partial initializer as well as a synthesized computed tuple property. It may also synthesize other memberwise features in the future as new ideas for them arise. The property list enables extremely concise yet expressive declarations of memberwise partial initializers. It is also possible to include several implicit property lists such as `members`, `vars`, `lets`, etc which would be quite similar to some of the ideas discussed in the review thread.

The proposal drafts can be found at the following links:

* Parameter forwarding: https://github.com/anandabits/swift-evolution/blob/parameter-forwarding/proposals/NNNN-parameter-forwarding.md
* Partial initializers: https://github.com/anandabits/swift-evolution/blob/partial-initializers/proposals/NNNN-partial-initializers.md
* Property lists: https://github.com/anandabits/swift-evolution/blob/property-lists/proposals/NNNN-property-lists.md

They contain enough detail about the proposed solution that I believe they are ready for a first round of discussion, however none are complete drafts. I will be starting a thread for each proposal. Please move discussion specific to each proposal into its respective thread.

Any discussion pertaining to memberwise intitialization, how these proposals address concerns brought up during the review, how well these proposals together provide a good long-term direction for memberwise intialization, etc can remain in one of the threads about the current proposal.

I want to thank you all again for participating. I'm very much looking forward to continuing the discussion.

Matthew


(Douglas Gregor) #19

  * What is your evaluation of the proposal?

It’s a well-considered and well-written proposal. I agree with the semantics of memberwise initializers (+1 to adding a reasonable implicit memberwise initializer for classes, and the ability to use default arguments in that implicit memberwise initializer). However, I would prefer to accept the semantics as improvements to the creation of the implicit memberwise initializer, so it’s a -1 to the “memberwise” specifier and “…” placeholder syntax.

Separately, I’m moderately nervous about the placeholder “…” getting overloaded with future intended uses for variadic generics and tuple packing/unpacking. I think the syntaxes will be distinct (“…” would always be attached to an existing parameter in the variadic-generics cases, and would be it’s own “parameter” for the memberwise initializer), but it could certainly be confusing.

  * Is the problem being addressed significant enough to warrant a change to Swift?

Yes, for the implicit memberwise initializer. The lack of default arguments in the implicit memberwise initializer comes up often as a feature request, and the lack of an implicit memberwise initializer for classes leads to a bunch of boilerplate for common use cases (particularly the “let’s create our first class” example, which needs to mention initializers far too early).

As for the “memberwise” specifier and placeholder syntax, I don’t think so. When the implicit memberwise initializer doesn’t suffice, I think it’s completely reasonable to write out a memberwise initializer directly. It’s still boilerplate, but the cases in which it happens aren’t so numerous that it’s worth having another initialization concept.

  * Does this proposal fit well with the feel and direction of Swift?

Yes. It’s eliminating boilerplate and making structs/classes more useful and more uniform.

  * How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Read through the proposal and some of the commentary and, err, I bear responsibility for the current implicit memberwise initializer semantics, and have been thinking about this problem on-and-off for a couple of years.

  - Doug

···

On Jan 6, 2016, at 2:47 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:


(Janosch Hildebrand) #20

* What is your evaluation of the proposal?

-1 with the "added convenience < introduced complexity" rationale that has been mentioned by a few people in this discussion.

At first I was interested in this proposal for the obvious reason of having previously written initializer "boilerplate" and like with any form of boilerplate instinctively desiring to be rid of it. However over the evolution and now review of this proposal I have become much more hesitant.

Firstly, from the discussion it has become clear that this is a hard issue to solve elegantly.

I mostly like the proposed syntax but it adds a lot of additional language surface with complicated semantics for ultimately limited benefit.
Many people (on both the +1 and -1 sides) seem to be agree that this is ultimately only a "partial" solution and that they would like additional capabilities. However from the proposal and the discussion it seems that those would require even more special behaviour and/or syntax, again adding a lot of additional complexity for limited usefulness.

Secondly, over the course of following this discussion I have become increasingly convinced that this is not as big an issue as I first thought.

At least for me it seems that the annoyance towards writing (some) initializers stems mostly from an instinctual reaction to having to perform a repetitive and menial task. Upon reflection it seems the actual mental and physical work is extremely minimal and it's mostly my annoyance at doing so that seems out of proportion. Very little of my time is ultimately spent writing trivial initialization code.

While these initializers are annoying to type out, it is not an error prone task. They are clear and easy to understand, requiring basically no mental overhead to "parse". They can be easily refactored and adapted as needs change.

With the proposal as it stands I can save a few keystrokes here and there. Until my initializer needs a bit of custom work at which point I might need to write it out anyway, use increasingly obscure syntax, start reordering the types properties, etc... The various extensions to this proposal increase the number of initializers that I could "simplify" but at the cost of a much more complex mental model. Now I need to take into account various attributes and declarations to make my initializer(s) work the way I want.

Writing the initializer is something that happens once, reading it will occur many times. And while it's nice to save 50 keystrokes when writing the thing, is it worth the mental overhead required to piece it together in the future?

The oft mentioned alternative `init(foo: Int, bar: Int) { // implicit }` improves on some of these aspects but at that point the work saved is so small as to probably not be worth the bother.

Now I'm not saying the answers here are clear cut but for me, for now, this proposal introduces a lot of complexity to solve a very limited subset of a not so big problem. But I'd be happy to see this topic revisited in the future and this detailed and well though out proposal should definitely be the starting point for any future discussions.

* Is the problem being addressed significant enough to warrant a change to Swift?

Judging from the interest in this topic, probably yes. However it is a minor problem and the current solutions are too costly for too little benefit.

* Does this proposal fit well with the feel and direction of Swift?

Syntactically mostly yes. However Swift strongly favors clarity and simplicity over conciseness and I feel this proposal has issues in that regard.

* If you have you used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

No.

* How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

I've read the proposal (an earlier draft and the current version) and followed the discussion.

- Janosch