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

David Owens II david at owensd.io
Fri Jan 8 12:51:44 CST 2016


> On Jan 8, 2016, at 9:31 AM, Matthew Johnson via swift-evolution <swift-evolution at swift.org> wrote:
> 
>> 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.

The struct memberwise behavior today is really simple and doesn’t expose a public API allowing for non-exhaustive behavior requirements and a much simpler design.

The struct rule is basically this:

A member is added to the initializer when the following conditions are true:
    1. The member is not declared with let and an initialization value
    2. The member is not a computed property

Also, this generated initializer is only generated when no other init() has been defined.

The really important observation though is that it keeps the generated initializer private, which means that there are no real API contracts to consider as it can only be used within your own code. It’s a nicety to have when simply building up some code to solve a problem.

The proposal essentially is doing two things:

    1. Create a way to generate a public API contract based on a series of fairly complicated rules, potential annotations, and member orderings within the type
    2. Generate the pass through of assignment for the parameters of the init() and their backing values.

The vast amount complexity comes from trying to solve #1.

As for this:

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


Paul, this has also bugged me too; I do not see how it is accurate. There aren’t N initializers, there is one initializer that must fully instantiate the type. Each type may have additional convenience initializers, but these are not required. Further, they cannot make use of the placeholder. There is a “futures” that talks about it, but that’s out of scope of the original proposal. 

Your example hear illustrates the complexity (slightly modified from your proposal’s usage):

struct Foo {
  let bar: String
  let bas: Int
  let baz: Double

  init(self bar: String, self bas: Int, bax: Int) {
    // self.bar = bar synthesized by the compiler
    // self.bas = bas synthesized by the compiler
    self.baz = Double(bax)
  }
}

The only thing I see your proposal removing is the re-typing of all of the members in the init signature that can be configured. And in fact, the current proposal doesn't support this. You have a futures section that looks a way to make this possible kinda like this:

struct Foo {
  let bar: String
  let bas: Int
  let baz: Double

  @nomemberwize(baz)
  memberwise init(..., bax: Int) {
    // self.bar = bar synthesized by the compiler
    // self.bas = bas synthesized by the compiler
    self.baz = Double(bax)
  }
}

-David

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


More information about the swift-evolution mailing list