[swift-evolution] Proposal: helpers for initializing properties of same name as parameters
Brent Royal-Gordon
brent at architechies.com
Sat Dec 5 16:31:11 CST 2015
> Did you read through by reply to the original proposal? I believe it provides the convenience you're looking for here while still allowing for the flexibility to avoid boilerplate in initializers that do more than just set properties.
I did, and I didn’t really like it. One of the syntaxes it proposed was strange and ad-hoc; the other was a fairly arbitrary overloading of parentheses, although it doesn’t actually conflict with anything since you can’t overload “calling parentheses” on a non-function.
It’s important to ensure that, when the implementation evolves, you can replace the initializer transparently. For instance, suppose I have a type which represents a player in a game. It uses a stored property called `points`:
class Player {
var name: String
private(set) var points: Int
func addPoints(additionalPoints: Int) {
points += additionalPoints
}
// Creates init(name: String, score: Int)
init default()
}
Later, I decide to add syncing, and realize I need to change this model. I need to add a sync identifier, and I want to change `points` to be computed from a series of `PointChange` objects. (This is a common strategy to avoid sync conflicts.) However, I don’t want to disrupt any of my existing code when I do this.
class Player {
let syncIdentifier = NSUUID()
var name: String
private var pointChanges: Set<PointChange>
var points: Int {
get { return pointChanges.reduce(0, combine: +) }
}
func addPoints(additionalPoints: Int) {
pointChanges.insert(PointChange(offset: additionalPoints)
}
// We can no longer use init default(), but we can still create an initializer with the same signature
init(name: String, points: Int) {
self.name = name
pointChanges = [ PointChange(offset: score) ]
}
}
By *not* separating the properties into a different syntactical construct from the constructor parameters, I can update my type’s implementation without affecting its interface. If properties were separated syntactically from constructor parameters as you proposed, it would not be possible to change this seamlessly.
> If you believe we should have a feature focused strictly on memberwise initializers and not also allow for less boilerplate in more sophisticated initializers I am interested to hear your rationale.
Honestly, I would like to fix the boilerplate issue in more sophisticated initializers, but I don’t see a clean way to do that. The other proposals I’ve seen in this thread, along the lines of:
init(self.name, self.points) {}
Frankly do too much violence to the parameter list. Swift’s declarations have a lovely feature where the declaration basically looks like the usage, except that the concrete values in the usage are replaced by types in the declaration. These proposals destroy that property—when I look at the declaration, I can no longer envision what the call site will look like.
Basically, I focused on default initializers because they’re *really* easy to solve and cover a good portion of the common case. I really have no idea how to solve the larger problem, and I haven’t liked any of the other ideas in this thread, but I do know how to solve this more limited problem.
--
Brent Royal-Gordon
Architechies
More information about the swift-evolution
mailing list