40

I am trying to provide a default implementation of protocol so it can satisfy multiple constraints from other protocols.

Given the following protocols:

public protocol Creature {
    var name: String { get }
    var canMove: Bool { get }
}

public protocol Animal: Creature {}

public protocol Moveable {
    var movingSpeed: Double { get set }
}

public protocol Agend {
    var aged: Int { get }
}

I'm able to extend using a single condition on Self:

// all animals can move
extension Moveable where Self: Animal {
    public var canMove: Bool { return true }
}

But how do I set constraints to provide a default Moveable implementation for types that conform to both Animal and Aged protocols? Something like below? Or is there some "add" "or" option for the where clause?

// Pseudocode which doesn't work
extension Moveable where Self: Animal && Self: Aged {
    public var canMove: Bool { return true }
}
Robin Daugherty
  • 7,115
  • 4
  • 45
  • 59
Audrey Li
  • 980
  • 2
  • 11
  • 14
  • By the way, to see the final code sample that I wrote, visit : http://audreyli.me/2015/06/29/strategy-design-pattern-updated-using-protocol-extension-in-swift-2-0/ – Audrey Li Feb 12 '16 at 20:20

4 Answers4

75

You could use a protocol composition:

extension Moveable where Self: protocol<Animal, Aged> {
    // ... 
}

Or just add the conformances one after the other:

extension Moveable where Self: Animal, Self: Aged {
    // ... 
}
ABakerSmith
  • 22,759
  • 9
  • 68
  • 78
  • 5
    This is great for when it must conform to both, but what about if you'd want to check for conformance for one OR the other? Something along the lines of: extension Movable where Self: protocol... – Dylan Mar 16 '16 at 23:11
  • 1
    @Dylan, instead of checking conformance, this syntax is used to say a type conforms to a protocol. To check conformance to a protocol take a look at AirspeedVelocity's answer here http://stackoverflow.com/questions/28124684/swift-check-if-generic-type-conforms-to-protocol – ABakerSmith May 09 '16 at 08:06
  • Apparently there is a new syntax, and the protocol<..> has been removed. Use the & syntax in Swift 4. – Glenn Howes Sep 18 '17 at 15:28
42

As of the time of this post, the answer is using protocol<Animal, Aged>.

In Swift 3.0, protocol<Animal, Aged> is deprecated.

The correct usage in Swift 3.0 is:

extension Moveable where Self: Animal & Aged {
    // ... 
}

You can also combine the protocols with a typealias. This is useful when you are using a combination of protocols in multiple places (avoids duplication and promotes maintainability).

typealias AgedAnimal = Aged & Animal
extension Moveable where Self: AgedAnimal {
    // ... 
}
kgaidis
  • 14,259
  • 4
  • 79
  • 93
  • 1
    I know some time has passed, but typealias types won't come across in Objective-C (e.g., for checking protocol conformance). I ended up doing this: `@objc public protocol AgedAnimal: Aged, Animal {} ` – balthisar Dec 13 '17 at 17:20
2

Since Swift 3 you can use typealias to create types that conform to multiple protocols:

typealias AgedAnimal = Animal & Aged

So your code would become:

extension Moveable where Self: AgedAnimal {
    // ...
}

Or like this:

typealias Live = Aged & Moveable

extension Animal where Self: Live {
    // ...
}
nslllava
  • 589
  • 2
  • 9
  • 19
0

Make the protocol become reference type

extension Moveable: AnyObject {}
FBC
  • 1,047
  • 8
  • 18