Cannot call across extensions with generic constraints

So I've got this class, and it's generic with respect to types that conform to some protocol.

However, I want to add some specific functionality if the type happens to conform to a specific sub-protocol.


So I've done that with an extension, like this:


protocol A
{
    func aFunction()
}

protocol B : A
{
    func bFunction()
}

class MyClass<T:A>
{
    var myVariable : T? = nil
   
    func doSomethingWithA()
    {
        myVariable?.aFunction()
    }
}

extension MyClass where T:B
{
    func doSomethingWithB()
    {
        myVariable?.bFunction()
    }
}

enum TestType : B
{
    case Someting
   
    func aFunction() { print("A function") }
    func bFunction() { print("B function") }
}

let testObj        = MyClass<TestType>()
testObj.myVariable = TestType.Someting

testObj.doSomethingWithB()


The problem is that I can't call the specific method outside of its extension. For example, I can't call doSomethingWithB() from doSomethingWithA().


I don't expect to be able to just call it like that, because doSomethingWithB won't exist if T doesn't conform to B. But I can't find any way to call it.


I suppose I'm looking for some way to locally narrow down the scope of T with a generic constraints list. I've tried to call an overloaded generic function (one overload for T:A and one for T:B), but if I call it from doSomethingWithA, the T:A version is called even though a more specific version is available. Is anything like this possible with Swift 2?


The reason why I'm doing this is because I want these specialised methods to hook in to the base implementation's loading cycle. I need to use generic constraints rather than declaring variables and parameters in terms of protocols because in my production code protocol A has an associated type and B uses Self.

I don't think it's possible. Or more accurately, it is possible for your example code, but not for protocols that have associated types.


Protocol extension methods are selected statically by the compiler based on the type information available at compile time. To call doSomethingWithB(), you must present the compiler with a known MyType<T: B>. The problem is that you can neither check a given T for B-conformance nor downcast yourself to a MyType<B>, because of the associated type requirement.


It depends on exactly what you're doing, but I think you'd be better off with a class hierarchy.

Yes, the problem is that this is already part of a class hierarchy. I wanted to add some specialised behaviour in one of the base classes (based on the type of T) which would then be inherited by all subclasses.


If I added a subclass instead (which only accepts T:B), I would basically be forking the class hierarchy, which isn't what I want.


i.e. with specialised extensions:


MyCollectionView<T>

MyCollectionView<T:Sectionable>

|

V

MyCollectionViewSubClass<T>

MyCollectionViewSubClass<T:Sectionable>


versus subclassing:


MyCollectionView<T> -> MyCollectionViewSubClass<T>

|

V

MySectionableCollectionView<T:Sectionable> -> MySectionableCollectionViewSubClass<T:Sectionable>

Cannot call across extensions with generic constraints
 
 
Q