Create generic object with subclass as parameter

Greetings.


I have run up against another generic brick wall, so to speak.


I have a generic class:


class Thing<ownerT>
{
  private var owner: ownerT

  init(owner: ownerT)
  {
    self.owner = owner
  }
}


Now I would like to use that type inside a generic protocol:


protocol Owner
{
  var thing: Thing<Self> { get set }
}


Next, I would like to implement that protocol in a hierarchy of classes, such that the "owner" passed to the generic class is the current subclass:


class Base : Owner
{
  var thing: Thing<Self> // meant to allow use of Derived but obviously this won't compile
}

class Derived : Base
{

}



Problem 1: the use of Self in the protocol makes its compulsory to use a final class to implement the protocol.


Problem 2: derived classes need to use Thing<…> as if it belonged to their concrete type, not Base.


Any bright ideas how I can get Derived to see Thing ?


If this were C#, I could bind the generic type to something akin to

type(of: self)


But this is Swift and I am struggling with the lack of dynamicism

Replies

Your code fragments have lost their "< T >" annotations, so it's hard to see exactly what you're trying to do. Can you edit your post to fix this?

Oops! Must have happened when copy/pasting. I've fixed it in my post.


Many thanks for looking at this Quincey

There's no good solution here. Owner isn't really a "generic protocol", and protocols don't really compose well with base classes, and abstract base classes don't really exist in Swift. I think the best you can do is something like this:


protocol Owner {
    var thing: Owned { get set }
}

protocol Owned {
    var owner: Owner { get set }
}

class Thing {
    private var owner: OwnerT
    init(owner: OwnerT) {
        self.owner = owner
    }
}

class Base: Owner {
    var thing: Owned
    init(thing: Owned) {
        self.thing = thing
    }
}

class Derived: Base {
    var derivedThing: Thing {
        return thing as! Thing
    }
}



In code that uses this, if you have a Base reference, you can get to the Thing, but you don't know what class it really is without casting. If you have a Derived reference, this gives it a convenience method that does the casting for you. (Alternatively, you could make "derivedThing" a stored property.)