Why can’t @propertyWrapper see computed property implementation provided by protocol extension?

I am trying to avoid boilerplate in writing many @propertyWrappers expected to provide access to the wrappedValue property via the static subscript (yes, the one still in beta). By the convention I learned from tutorials, I wish the wrappedValue property to be unavailable, i.e.

var wrappedValue: SomeType { get { fatalError() } set { fatalError() } }

In my limited Swift vocabulary, I thought this is a problem you could solve via a default implementation to a protocol, as provided via an immediate extension to that protocol. For example, the following trivially works:

protocol ComputedPropertyProtocol {
    associatedtype PropertyType
    var value: PropertyType { get set }
}

extension ComputedPropertyProtocol {
    var value: PropertyType { get { fatalError() } set { fatalError() } }
}

struct AllIGotIsALousyPropertyImplementation: ComputedPropertyProtocol {
    typealias PropertyType = UInt
}

let a = AllIGotIsALousyPropertyImplementation()

print(a.value) // Generates "Fatal error" and that’s OK!

Next, I thought of using the same technique to boilerplate-away that wrappedValue property on my @propertyWrapper, but this did not work:

protocol SubscriptOnlyPropertyWrapper {
    associatedtype PropertyType
}

extension SubscriptOnlyPropertyWrapper {
    var wrappedValue: PropertyType {
        get { fatalError() }
        set { fatalError() }
    }
}

@propertyWrapper
struct MyFirstAttempt: SubscriptOnlyPropertyWrapper {
    typealias PropertyType = UInt
}

The compiler complains that it can’t find the wrappedValue property:

expression failed to parse:
error: PropertyWrappers.playground:13:8: error: property wrapper type 'MyFirstAttempt' does not contain a non-static property named 'wrappedValue'
struct MyFirstAttempt<Value>: SubscriptOnlyPropertyWrapper {
       ^

OK, so I thought generics might nudge the compiler so I tried declaring the @propertyWrapper as a generic:

@propertyWrapper
struct MyFirstAttempt<Value>: SubscriptOnlyPropertyWrapper {
    typealias PropertyType = Value
}

...to then clear the error by being explicit about the type, i.e. @MyFirstAttempt<UInt>. But I never get to that point. The compiler still doesn't see the default implementation for the wrappedValue property.

Why would @propertyWrapper prevent this technique from working?

Based on my very limited experience with Swift, it seems that @propertyWrapper should have been a protocol (like Codable), and the language should have gained a new keyword/attribute to limit/allow protocol compliance only for struct rather than class. Something like @structOnly protocol SomeProtocol (or imagine if something like protocol PropertyWrapper where is struct would be legal) might have been useful for more than one language feature... instead we got another attribute with narrow scope that seems to alter expected language behavior. Hope I'm missing something obvious which wouldn't be surprising.

Thank you!

3 Likes