Immutable setters

Idea brought up on Swift Evolution by Zsolt Szatmari:

The only thing I am really missing right now from Swift is described as following. This works in some other languages, e.g.  F#, Kotlin, and Haskell.

let john = {firstName="John"; lastName="Doe"}
let alice = {john with FirstName="Alice"}
Current way to do this in Swift is:
let john = (firstName:"John", lastName:"Doe")
var alice = john
alice.firstName = "Alice"
This might seem to be a nuance, but it’s more cumbersome (especially if one wants to do this frequently), and we are left with a var at the end.  Also, this idea rhymes with the current direction of removing var arguments from functions.

Unless I am overlooking something major here (wouldn’t be the first time), there’s actually a pretty easy way to do this in existing Swift:

struct Person {
    var firstName, lastName: String
}

let john = Person(firstName: "John", lastName: "Doe")

func modify(item: T, update: (inout T) -> Void) -> T {
    var this = item
    update(&this)
    return this
}

let carol: Person = modify(john) { $0.firstName = "Carol" }

print(carol) // Person(firstName: "Carol", lastName: "Doe")

The `modify()` function makes a new copy, applies any changes, and returns the new instance. Swift’s type inference system ensures that the  associated closure can access instance members.

One Comment