[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