Property Wrappers enclosing self only work with reference types?

Am I correct in seeing that property wrappers that enclose self only work with reference types, and not value types?

Imagine this setup:

public protocol LazyDecodable {
    var backingStorage: [String: Any] { get set }
    init?(backingStorage: [String: Any])
}

@propertyWrapper
public struct LazyDecode<Value: LazyDecodable> {
    public let field: String
    public var wrappedValue: Value? {
        get { fatalError() }
        set { fatalError() }
    }
    
    public static subscript<Instance: LazyDecodable>(
        _enclosingInstance instance: Instance,
        wrapped wrappedKeyPath: ReferenceWritableKeyPath<Instance, Value>,
        storage storageKeyPath: ReferenceWritableKeyPath<Instance, Self>
    ) -> Value? {
        get {
            let wrapper = instance[keyPath: storageKeyPath]
            return (instance.backingStorage[wrapper.field] as? [String: Any]).flatMap { Value.init(backingStorage: $0) }
        }
        set {
            let wrapper = instance[keyPath: storageKeyPath]
            instance.backingStorage.updateValue(newValue?.backingStorage, forKey: wrapper.field)
        }
    }
}

From my understanding, I cannot make this work because the static subscript requires ReferenceWritableKeyPath values, and you cannot pass a value as inout via subscript, which means enclosing self only works on reference types.

Am I reading this correctly?

If I'm missing something, what is it?

If I'm not missing anything, do we have plans to address this? And did we miss this during the initial review, or did we intentionally not want this?

2 Likes

Yeah, this is a limitation of the existing design (which is one of many reasons it's not an official feature yet). Properly allowing writable access to self from a property wrapper, because of inout exclusivity, requires that the access to the property can be well-nested inside the outer access to self in a way that's hard to express in the language today, since we don't have inout subscript arguments, nor any way to express a property- or subscript-like storage entity that exists on a type that isn't the current Self type in a type declaration.

5 Likes

Awesome, thanks for clarifying. I guess I'll wait for the next round of property wrapper evolution to come up again.