1

I'm trying to implement a not trivial (at least for my level) relationship between types.

Class A and B are subclasses of a class MySuperClass, and I'm letting them implement a protocol "MyProtocol"

class MySuperclass {...}

protocol MyProtocol {
     func myProtocolMethod() 
}

class A:MySuperclass, MyProtocol {...}

class B:MySuperclass, MyProtocol {...}

My class "Container" has a variable x, which can be either an instance of A or B

class Container {... var x:???? ....}

As maybe imaginable from the ???? my problem is that I would like that I can use x as both as MyProtocol and MySuperclass.

Just today I solved a very similar problem in this thread and I thought I could apply that here but I'm not succeeding.

The idea would be to declare the type of the variable such that it satisfies a constraint <T where T:MySuperclass, T:MyProtocol>, but where do I put that? Everything I have tried so far didn't really make sense and failed.

I tried, for example:

class Container<T where T:MySuperclass, T:MyProtocol>

class Container {... var x:T ...}

but I instantiate and assign T in Container, and when I do this I get a compiler error:

class Container {... self.x = A() ....}

"Type A is not convertible to 'T'"

But actually it should, because A satisfies the type constraints.

Edit: Thanks to arshajii's anwer I understood why this is not possible. But I still need to know how to solve my initial problem.

I don't know if generics is actually the correct approach for this. I think I don't really need a type variable, what I need is rather something like an aggregate type...

Edit 2- I know I can implement this by just implementing a subclass. Was just wondering if there are other approaches. But thinking again a subclass seems to be the best way.

Thanks in advance.

Community
  • 1
  • 1
User
  • 31,811
  • 40
  • 131
  • 232

3 Answers3

3

T could be another type (e.g. FooImpl2) completely unrelated to FooImpl:

           Foo
          /   \
    FooImpl   FooImpl2

A Foo instance cannot be assigned to a (potential) variable of type FooImpl2, hence the error.

arshajii
  • 127,459
  • 24
  • 238
  • 287
  • Thanks! (+1) now I get that part. But I still don't know how to solve my original problem :/ Maybe I should remove the Java tag as the solution of that one needs Swift expertise. – User Jan 15 '15 at 21:11
0

This is just one of strategies to workaround this kind of problems.

// declare Protocol of MySuperClass type
protocol MySuperClassType {
    func mySuperClassMethod()
}

// Make the superclass conforms to it.
class MySuperclass: MySuperClassType {
//                  ^^^^^^^^^^^^^^^^
    func mySuperClassMethod() {}
}

protocol MyProtocol {
    func myProtocolMethod()
}

class A: MySuperclass, MyProtocol {
    func myProtocolMethod() { }
}

class B: MySuperclass, MyProtocol {
    func myProtocolMethod() { }
}

class Container {

    // use "Protocol Composition" to declare the property.
    var x: protocol<MySuperClassType, MyProtocol>

    // ...
}
rintaro
  • 51,423
  • 14
  • 131
  • 139
  • The problem with this, in my particular case, is that I want the variable to be usable by existing apis as an instance of MySuperClass. An example: If MySuperClass is an UIView, even if I create an extension to make x conform to a protocol "MySuperClassType" with UIView methods, I can't do view.addSubview(x). – User Jan 16 '15 at 11:22
  • Then you should take another strategy, something like: http://stackoverflow.com/questions/26474061/whats-the-swift-equivalent-of-declaring-typedef-someclasssomeprotocol-mytype/26475054#26475054 – rintaro Jan 16 '15 at 11:30
0
class Container {... var x: protocol<MySuperclassProtocol, MyProtocol> ....}

Ensure that MySuperclass conforms to MySuperclassProtocol

Vatsal Manot
  • 17,695
  • 9
  • 44
  • 80
  • The problem with this, in my particular case, is that I want the variable to be usable by existing apis as an instance of MySuperClass. An example: If MySuperClass is an UIView, even if I create an extension to make x conform to a protocol "MySuperClassType" with UIView methods, I can't do view.addSubview(x). – User Jan 16 '15 at 11:28
  • `view.addSubview(unsafeBitCast(x, UIView.self))` – Vatsal Manot Jan 16 '15 at 11:33
  • I assumed that you were not aware of `unsafeBitCast`. I've tried to tackle this problem myself, but haven't found a concrete solution yet. – Vatsal Manot Jan 16 '15 at 11:35
  • Swift protocols do not support subclass dependencies as of yet. – Vatsal Manot Jan 16 '15 at 11:37