Implement generic method from protocol in a generic class


(Joanna Carter) #22

Unfortunately, that's not going to work :disappointed:

Each concrete type will need a PropertyBag, created from its list of key paths. But, I only want to create and hold the PropertyBag in the ancestor Object class, to avoid having to write the same boilerplate in every concrete class.

open class Object
{
  public var propertyBag: PropertyBag<what type goes here?>
  
  // …

(Anthony Latsis) #23

You don't have to. Have I written any boilerplate code in Person?


(Joanna Carter) #24

No, I hadn't seen the generic parameter on Object in your code.

However, adding that parameter then causes problems with constraints elsewhere:

extension KeyPath where Root : Object<Root> & KeyPathDeclaration, Value : DefaultValueProvider *** error
{
  static func createProperty() -> PropertyProtocol
  {
    return Property<Value>()
  }
}

error - Superclass constraint 'Root' : 'Object<τ_0_0>' is recursive

Likewise here:

extension PropertyBagFactory where Self : Object<Self> & KeyPathDeclaration
{

(Anthony Latsis) #25

One thing that comes to mind is to abstract over Object with a protocol interface:

protocol ObjectProtocol {
  associatedtype ownerT
  var propertyBag: PropertyBag<ownerT> { get set }
}

open class Object<ownerT>: ObjectProtocol { ... }

The goal is to leverage the flexibility we gained by slightly loosening the constraints to avoid (this time implicitly) recursing on the superclass again, since we already know that is danger zone.

extension PropertyBagFactory
where Self : ObjectProtocol & KeyPathDeclaration,
      Self.ownerT == Self {} // Too tight

extension KeyPath
where Root : ObjectProtocol & KeyPathDeclaration,
      Value : DefaultValueProvider,
      Root.ownerT == Root {} // Too tight

extension PropertyBagFactory
where Self : ObjectProtocol & KeyPathDeclaration,
      Self.ownerT : ObjectProtocol {} // Ok

extension KeyPath
where Root : ObjectProtocol & KeyPathDeclaration,
      Value : DefaultValueProvider,
      Root.ownerT : ObjectProtocol, {} // Ok

You can try leaving Root.ownerT == Root. Apparently, unlike Self, this is a circularity the compiler is able to resolve.