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

plx plxswift at icloud.com
Sat Jan 9 07:36:50 CST 2016


> On Jan 8, 2016, at 12:51 PM, Matthew Johnson <matthew at anandabits.com> wrote:
> 
> Are you suggesting that this attribute would be applied to a specific initializer?  Or would this be shared by all memberwise initializers of the type in some way?

I meant it as a type-level declaration.

The mental model here is that in many cases, a type with multiple public initializers winds up (or at least should wind up) like this:

- there’s a common “package” comprised of:
  - the input parameters (e.g. init args)
  - the boilerplate assignments (in the init)
- each init has some additional parameters/logic not shared with the other

For another example, this is lightly-adapted from actual code:

class PlayerItemWrapper : NSObject {
  let previewInfo: PreviewInfo
  let itemDescriptor: ItemDescriptor
  let metricCollector: MetricCollector
  let playerItem: AVPlayerItem

  // assume trivial assignments followed by observation-setup logic:
  required init(previewInfo: PreviewInfo, itemDescriptor: ItemDescriptor, metricCollector: MetricCollector, playerItem: AVPlayerItem)

  // these exist for convenience only; we have them b/c we don’t want to directly use
  // the corresponding AVPlayerItem convenience methods, since we also want to
  // control some of automatically loaded keys (etc.)
  convenience init(previewInfo: PreviewInfo, itemDescriptor: ItemDescriptor, metricCollector: MetricCollector, asset: AVAsset)
  convenience init(previewInfo: PreviewInfo, itemDescriptor: ItemDescriptor, metricCollector: MetricCollector, assetURL: NSURL)
  convenience init(previewInfo: PreviewInfo, itemDescriptor: ItemDescriptor, metricCollector: MetricCollector, assetDescriptor: AssetDescriptor)
}

…where you can easily see these inits have the structure of a “common package” + per-init details.

Under the organization above, it then makes sense to me to have a type-level declaration that is able to declare that type’s “official” common package, which would let the above be condensed into something like:

class PlayerItemWrapper : NSObject {
  @memberwise(previewInfo, itemDescriptor, metricCollector)
  // ^ need to be explicit here to *omit* playerItem, unless we
  //   also plan to immediately have an @nomemberwise declaration
  //   we can apply to individual properties
  let previewInfo: PreviewInfo
  let itemDescriptor: ItemDescriptor
  let metricCollector: MetricCollector
  let playerItem: AVPlayerItem

  // assume trivial assignments followed by observation-setup logic:
  memberwise required init(..., playerItem: AVPlayerItem)

  // these exist for convenience only (and would need a way to forward the … 
  // to the required init, e.g. `self.init(…, playerItem: _)`, which is seems to be
  // noted as a future direction in the current proposal
  memberwise convenience init(…, asset: AVAsset)
  memberwise convenience init(..., assetURL: NSURL)
  memberwise convenience init(..., assetDescriptor: AssetDescriptor)
}

…and because writing out such parameter lists explicitly is a bit of a pain, the hope is that it’d also be possible to simply write e.g. @memberwise w/out an explicit list and get some automatically-inferred list synthesized on your behalf wherever possible.

Hope this clears up the kind of thing I was trying to sketch earlier. It is at a different point in the flexibility/feature spectrum for sure, and not thought-through too thoroughly either.

I also made a significant earlier error: it shouldn’t be an error if some @memberwise’s $parameterList was *incomplete*, the only error is if it contains invalid/unrecognized names.

> I don’t think applying this to a specific initializer gains enough over just writing the initializer manually to be worthwhile.  If we were going to do something specific to a single initializer, something along the lines of David’s suggestion makes the most sense to me.
> 
> On the other hand, if you are suggesting something type-wide that would be shared by all memberwise initializers, this is really an alternate way to accomplish an opt-in model.  Rather than applying an attribute to properties you would have a declaration specify which properties are included in memberwise initializers, with the ability to specify order, labels, and defaults if necessary.  

This is what I meant, essentially. An explicit @memberwise as per the above saves minimal effort if you had to do it on a per-init basis, but in scenarios with a bunch of basic parameters + various convenience inits for the remaining parameters it could still be a net win.

> That might be a reasonable syntax for an opt-in model.  As noted in the proposal, an opt-in model could be added by a future enhancement and would be used in place of the automatic model if the opt-in syntax was present.

If this goes anywhere I am hoping someone will improve the syntax, actually, what I sketched seems clunky and non-idiomatic.

In any case, having seen how this discussion has gone I think it’s safe that at least in hindsight starting from the purely-automatic/purely-inferred synthesis standpoint may ultimately have made this proposal than it needs to have been.

It’s a *really* good goal — I’d like to be able to get the memberwise init synthesized automatically where possible! — and I think within the design constraints you’ve been working under it may not be possible to do it that much better than as per your proposal…but I think the conclusion here is that “it seemed plausible to extend the memberwise-init synthesis like this, but if you work through it in enough detail to make it concrete, it has a surprising amount of intrinsic complexity/inference rules/edge-cases to worry about”.

That’s my overall 2c here (along with what’s in the earlier emails).

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


More information about the swift-evolution mailing list