Search code examples
swiftprotocolsextension-methodsswift4swift-extensions

In Swift 4, can you write an extension that applies only to things that adhere to multiple protocols?


Consider these protocols

protocol NamedThing{
    var name:String{ get }
}

protocol ValuedThing{

    associatedtype ValueType

    var value:ValueType{ get }
}

And these structs...

struct TestThingA : NamedThing {
    let name = "TestThing"
}

struct TestThingB : ValuedThing {

    typealias ValueType = Int

    let value = 4
}

struct TestThingC : NamedThing, ValuedThing {

    typealias ValueType = Int

    let name = "TestThing"
    let value = 4
}

I'm trying to write an extension that would only apply to struct TestThingC because it adheres to both protocols.

None of these work, of course...

extension NamedThing & ValuedThing{
    func test(){
        print("Named thing \(name) has a value of \(value)")
    }
}

extension Any where NamedThing & ValuedThing {
    func test(){
        print("Named thing \(name) has a value of \(value)")
    }
}

extension Any where Self is NamedThing, Self is ValuedThing{

    func test(){
        print("Named thing \(name) has a value of \(value)")
    }
}

extension Any where Self == NamedThing, Self == ValuedThing{

    func test(){
        print("Named thing \(name) has a value of \(value)")
    }
}

So how does one write an extension that applies to items which adhere to both (multiple) protocols?


Solution

  • You could define a restricted extension to one of the protocols:

    extension NamedThing where Self: ValuedThing {
        func test(){
            print("Named thing \(name) has a value of \(value)")
        }
    }
    
    TestThingC().test() // compiles
    
    TestThingA().test() // error: Type 'TestThingA' does not conform to protocol 'ValuedThing'
    TestThingB().test() // error: Value of type 'TestThingB' has no member 'test'