Basically my idea was to have like generic Builder protocol. I wanted to have pre implemented set method with keyPath. For some reason it doesn't compile with error message: "Cannot assign through subscript: 'self' is immutable" even though extension is only for AnyObject so self should be mutable. Side note: I also tried version without casting to ReferenceWritableKeyPath with same error. Is anyone have idea how I can make this work or explanation why it's not working?
protocol Builder {
associatedtype Result
func set<T>(_ keyPath: WritableKeyPath<Self, T>, to value: T) -> Self
func build() -> Result
}
extension Builder where Self: AnyObject {
func set<T>(_ keyPath: WritableKeyPath<Self, T>, to value: T) -> Self {
if let path = keyPath as? ReferenceWritableKeyPath<Self, T> {
self[keyPath: keyPath] = value
}
return self
}
}
Playing around with code derived from your code above, putting in this line of code shown below as the very first line of the extension gets rid of that error saying that self is immutable.
Thanks for the replays @Shinehah-Gnolaum and @sveinhal. Builder is gone be a class, because it usually mutates during it's lifetime. Overall I found a solution with ReferenceWritableKeyPath that really suits my needs. Haven't used it in prod, but tested on some examples. Here it is:
protocol Builder: AnyObject {
associatedtype Result
func set<T>(_ keyPath: ReferenceWritableKeyPath<Self, T>, to value: T) -> Self
func build() -> Result
}
extension Builder {
func set<T>(_ keyPath: ReferenceWritableKeyPath<Self, T>, to value: T) -> Self {
self[keyPath: keyPath] = value
return self
}
}
struct Person {
let name: String
let age: Int
let adress: String
}
final class PersonBuilder: Builder {
var name: String = ""
var age: Int = 0
var adress: String = ""
func build() -> Person {
Person(name: name, age: age, adress: adress)
}
}
PersonBuilder()
.set(\.name, to: "Jhon")
.set(\.adress, to: "street 1")
.set(\.age, to: 25)
.build()