25

Is it possible to add protocol compliance to a different protocol by way of an extension?

For instance we would like A to comply with B:

protocol A {
  var a : UIView {get}
}

protocol B {
  var b : UIView {get}
}

I want to give a default implementation (compliance) of B to objects of type A

// This isn't possible
extension A : B {
  var b : UIView {
    return self.a
  }
}

The motivation being to reuse objects of A in cases where a B is required without creating my own "bridge"

class MyClass {
  func myFunc(object : A) {
    ...
    ...
    let view = object.a 
    ... do something with view ...

    myFunc(object)      // would like to use an 'A' without creating a 'B'
  }

  func myFunc2(object : B) {
    ...
    ...
    let view = object.b
    ... do something with view ...

  }
}

As a side note we can extend a class to implement a protocol

class C {
  let C : UIView
}

// this will work
extension C : B {
  var B : UIView {
    return self.c
  }
}

and protocols can give default implementations

extension A {
  // a default implementation
  var a : UIView {
     return UIView()
  }
}
Avba
  • 14,822
  • 20
  • 92
  • 192

2 Answers2

21

When extending A, you could specify that the type also conforms to B:

extension A where Self: B {
    var b : UIView {
        return self.a
    }
}

Then make your type conform to A and B, e.g.

struct MyStruct : A, B {
    var a : UIView {
        return UIView()
    }
}

Due to the protocol extension, instances of MyStruct will be able to use a and b, even though only a was implemented in MyStruct:

let obj = MyStruct()
obj.a
obj.b
ABakerSmith
  • 22,759
  • 9
  • 68
  • 78
  • 3
    I've used the "where Self:B..." in the past but it still requires defining your "MyStruct". "MyStruct" is a "one use" bridge which entails boiler plate code. I'm looking for the most concise way , such that I don't have to create an intermediary construct to perform the mapping. Ideally I would be able to extend the protocol , in the way we can extend a class or a struct. – Avba May 23 '16 at 13:17
  • I'm a bit confused, in that case could you not combine using `where Self:B` and a protocol extension? – ABakerSmith May 28 '16 at 22:20
  • @ABakerSmith have you tried compile above code? I also tried this approach but the compiler still kept telling MyStruct doesn't conform to protocol B. My protocol B is from third party and written in Objective C. – Mingming Jun 25 '16 at 11:35
  • @Flow, yes the code compiles for me. Are sure you're correctly implementing the requirements of your protocol `B` in the extension of `A`? – ABakerSmith Jun 25 '16 at 12:25
  • @ABakerSmith thanks for your reply. It did compile in my demo projects using pure Swift. However, I found, if protocol B is declare in Objective-C, the project won't compile. (That's unfortunately is my case, the protocol is from third party) I created a demo project here https://github.com/linktoming/Protocol-Demo the protocol C is in written in Objective-C in the demo. – Mingming Jun 25 '16 at 14:53
  • @Flow, taking a look at the project it seems like the real problem is you can't mark the `c` method (from protocol `C`) with `@objc` in the extension of `A`. It might be worth posting a question on this topic. – ABakerSmith Jun 25 '16 at 15:17
  • @ABakerSmith ok, I posted a question [here](http://stackoverflow.com/questions/38040211/how-to-provide-default-implementation-of-an-objective-c-protocol-in-a-swift-prot), please feel free to modify it to describe the problem better. – Mingming Jun 26 '16 at 15:44
5

You can make A inherits from B:

protocol A: B { var a: String { get } }
protocol B    { var b: String { get } }

// Default implementation of property b
extension A {
    var b: String { get { return "PropertyB" } }
}


class MyClass: A {
    var a: String { get { return "PropertyA" } }

    func printA(obj: A) {
        print(obj.a)
        printB(obj)
    }

    func printB(obj: B) {
        print(obj.b)
    }
}

let obj = MyClass()
obj.printA(obj)

Since A inherits from B, every property in B is available in A.

Code Different
  • 90,614
  • 16
  • 144
  • 163
  • 7
    This is fundamentally different than what the OP is asking. If he doesn't have control of `A` or `B`, this won't be of much help. – Charles A. May 19 '16 at 15:44
  • Then I suppose you can make a protocol `C` that implements both `A` and `B`, with default implementations as needed? – Code Different May 19 '16 at 15:47
  • 3
    I don't want to create extra protocols. – Avba May 19 '16 at 16:15
  • 2
    Then you are asking an [XY question](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) – Code Different May 19 '16 at 16:18
  • 1
    @CodeDifferent have you tried compile above code? I was trying the same approach but the compiler kept telling class A doesn't conform to protocol B in Swift 2. – Mingming Jun 25 '16 at 11:29