Conforming to protocols via @dynamicMemberLookup

I'd like to be able to write the following code:

protocol Named {
  var name: String { get }
}

struct Model: Named {
  var name: String
}

@dynamicMemberLookup
struct WrappedModel: Named {
  var model: Model

  subscript<T>(dynamicMember keyPath: KeyPath<Model, T>) -> T {
      return model[keyPath: keyPath]
  }
}

let wrapper = WrappedModel(model: Model(name: "cocoafrog"))

However, on the line WrappedModel: Named I get a compiler error

Type 'WrappedModel' does not conform to protocol 'Named'

I don't fully understand why this is not possible. After all, after the above code, I can access a name property of type String on the variable wrappedModel:

wrappedModel.name

Why does the protocol conformance fail in this case? Is this an intentional limitation or a bug?

3 Likes

Using @dynamicMemberLookup doesn’t actually add properties to the type, it only lets you use property syntax to access what’s really a subscript under the hood. So when you write wrapped.name it’s translated to wrapped[dynamicMember: \.name]. But the Named protocol requires an actual property called name to be there. At least that’s my understanding.

Depending on what you’re trying to do, another way to model this might be using conditional conformances:

struct Wrapped<T> {
  var wrapped: T
}

extension Wrapped: Named where T: Named {
  var name: String {
    return wrapped.name
  }
}
2 Likes