Builder pattern with fluid syntax, mutating temporary values?

This is a common pattern in some other languages. Is there a best way to do it in Swift? I like structs but you run into a problem with immutable temporaries.

I suppose the options to fix the error below are:

  1. Use a class.
  2. Make changeStuff() non-mutating and return a new Builder instead. I worry about efficiency.

In this case, should the compiler allow you to mutate the temporary?

struct Builder {
    var stuff: Int = 0
    mutating func changeStuff() -> Builder {
        stuff += 1
        return self
    }
}

func startBuilder() -> Builder {
    Builder(stuff: 0)
}

// Okay:
var b = startBuilder()
b.changeStuff()
let result = b.stuff
print(result)

// But fluid syntax doesn't work:
// Cannot use mutating member on immutable value: 'startBuilder' returns immutable value
let result2 = startBuilder().changeStuff().stuff
print(result2)
1 Like

Your changeStuff() method mutates in-place, but then returns a copy (structs are value types, so the return will create a new copy). So even in your "Okay" example, the compiler will probably warn you that the copy returned by b.changeStuff() is unused. So the solution is to implement two different methods (one of these, or both), depending on what you want, e.g.:

mutating func change() {
  stuff += 1
}

func changed() -> Builder {
  var changedCopy = self
  changedCopy.stuff += 1
  return changedCopy
}
2 Likes