Why does a keyPath subscript on an instance of a class require a mutatable variable?


(Joannis Orlandos) #1

I can imagine a setter being mutating for structs, but this does not apply to reference types since you're not modifying the reference but something inside the instance. Is this a bug in the compiler's parsing of the keyPath access?


(Adrian Zubarev) #2

Mind providing a small example how to reproduce the issue you're facing?


(Joannis Orlandos) #3

Hello @DevAndArtist, it's been a while since I saw your name!

func setValue<Value>(_ value: Value, forKey path: WritableKeyPath<MyClassType, Value>) {
    self[keyPath: path] = value
}

The above doesn't compile because self is not mutable.

func setValue<Value>(_ value: Value, forKey path: WritableKeyPath<MyClassType, Value>) {
    var me = self
    me[keyPath: path] = value
}

This doesn't make sense to me, since MyClassType is a class, so mutating access shouldn't be required here.


(Adrian Zubarev) #4

Yeah, I'm not part of the server slack workspace anymore, but constantly active in the forums.

I think you're hitting the same issue as I recently did. Have you tried ReferenceWritableKeyPath instead of WritableKeyPath since you're operating on a reference type?!


(Joe Groff) #5

A WritableKeyPath is a key path that modifies its root value in-place. Even on a class type, a WritableKeyPath could rebind the reference, which would require that the variable containing the reference be mutable. For instance, if we added the identity key path, it would be a WritableKeyPath, and you wouldn't want to be able to allow changing an immutable class reference through it:

let x = NSObject()
x[keyPath: \.self] = NSObject()  // \.self is a WritableKeyPath, but `x` can't be rebound

A ReferenceWritableKeyPath modifies state through a reference, such as a class reference, and does not modify that reference, which is what you want when talking about mutable class properties.