150

Let's say I have these protocols:

protocol SomeProtocol {

}

protocol SomeOtherProtocol {

}

Now, if I want a function that takes a generic type, but that type must conform to SomeProtocol I could do:

func someFunc<T: SomeProtocol>(arg: T) {
    // do stuff
}

But is there a way to add a type constraint for multiple protocols?

func bothFunc<T: SomeProtocol | SomeOtherProtocol>(arg: T) {

}

Similar things use commas, but in this case, it would start the declaration of a different type. Here's what I've tried.

<T: SomeProtocol | SomeOtherProtocol>
<T: SomeProtocol , SomeOtherProtocol>
<T: SomeProtocol : SomeOtherProtocol>
Logan
  • 52,262
  • 20
  • 99
  • 128

4 Answers4

289

You can use a where clause which lets you specify as many requirements as you want (all of which must be fulfilled) separated by commas

Swift 2:

func someFunc<T where T:SomeProtocol, T:SomeOtherProtocol>(arg: T) {
    // stuff
}

Swift 3 & 4:

func someFunc<T: SomeProtocol & SomeOtherProtocol>(arg: T) {
    // stuff
}

or the more powerful where clause:

func someFunc<T>(arg: T) where T:SomeProtocol, T:SomeOtherProtocol{
    // stuff
}

You can of course use protocol composition (e.g., protocol<SomeProtocol, SomeOtherProtocol> ), but it's a little less flexible.

Using where lets you deal with cases where multiple types are involved.

You may still want to compose protocols for reuse in multiple places, or just to give the composed protocol a meaningful name.

Swift 5:

func someFunc(arg: SomeProtocol & SomeOtherProtocol) { 
    // stuff
}

This feels more natural as the protocols are next to the argument.

Martin
  • 85
  • 8
Jiaaro
  • 74,485
  • 42
  • 169
  • 190
  • Geez this isn't logical, but good to know I just want to be one of the thanks spammers for this one, havent' realised this in a month since I needed it. – Mathijs Segers Apr 28 '15 at 13:11
  • 3
    Any way to do the same thing with classes and structs in the type contraint expression? e.g. ``? For classes the compiler appears to interpret this as saying "T is a subclass of both", and for structs it just complains that `"Type 'T' constrained to non-protocol type"`. – sleep Nov 12 '15 at 21:27
  • For the specific example in the OP:s question protocol composition _should_ be preferable method: the solution above is valid, but, imho, unnecessarily clutters the function signature. Also, using protocol composition as, e.g., a type constraint, still lets you use the `where` clause for additional type/other usage, e.g. `func someFunc where T.SubType == U>(arg: T, arg2: U) { ... }` for typealias `SubType` in e.g. `SomeProtocol`. – dfrib Feb 05 '16 at 15:17
  • @dfri this is the answer to the question that was asked - I would probably use protocol composition in my code (though not in the function signature, I'd give it a name in most cases) – Jiaaro Feb 05 '16 at 16:20
  • @Jiaaro I'd say this is _one_ answer to the question asked (the answer below shows another one). My comment were mostly related to the edit addition of the answer, namely _"Using `where` let's you deal with cases where there are multiple types involved"_, as this could possibly be interpreted (in this context)---by new Swift users reading this highly up-voted answer---as saying that you cannot combine the `where` versatility with protocol composition (which you naturally can: as shown in my comment above). – dfrib Feb 05 '16 at 16:26
  • 1
    Looks like this is deprecated in swift3 and recommends to use: func someFunc(arg: T) where T:SomeProtocol, T:SomeOtherProtocol { – Cristi Băluță Oct 19 '16 at 08:48
  • 2
    Is there a way to tell swift that T needs to be of a certain object type AND implement a certain protocol? – Georg Feb 01 '17 at 12:11
74

You have two possibilities:

  1. You use a where clause as indicated in Jiaaro's answer:

    func someFunc<T where T : SomeProtocol, T : SomeOtherProtocol>(arg: T) {
        // do stuff
    }
    
  2. You use a protocol composition type:

    func someFunc<T : protocol<SomeProtocol, SomeOtherProtocol>>(arg: T) {
        // do stuff
    }
    
Jean-Philippe Pellet
  • 59,296
  • 21
  • 173
  • 234
19

The evolution to Swift 3.0 brings some changes. Our two choices now look a little different.

Using a where clause in Swift 3.0:

The where clause has now moved to the end of a function signature to improve readability. So multiple protocol inheritance now looks like this:

func someFunc<T>(arg: T) where T:SomeProtocol, T:SomeOtherProtocol {

}

Using the protocol<> construct in Swift 3.0:

Composition using the protocol<> construct is being deprecated. The earlier protocol<SomeProtocol, SomeOtherProtocol> now looks like this:

func someFunc<T:SomeProtocol & SomeOtherProtocol>(arg: T) {

}

References.

More info on the changes for where are here: https://github.com/apple/swift-evolution/blob/master/proposals/0081-move-where-expression.md

And, more on the changes for the protocol<> construct are here: https://github.com/apple/swift-evolution/blob/master/proposals/0095-any-as-existential.md

ncke
  • 1,084
  • 9
  • 14
18

Swift 3 offers up to 3 different ways to declare your function.

protocol SomeProtocol {
    /* ... */
}

protocol SomeOtherProtocol {
    /* ... */        
}

1. Using & operator

func someFunc<T: SomeProtocol & SomeOtherProtocol>(arg: T) {
    /* ... */
}

2. Using where clause

func someFunc<T>(arg: T) where T: SomeProtocol, T: SomeOtherProtocol {
    /* ... */
}

3. Using where clause and & operator

func someFunc<T>(arg: T) where T: SomeProtocol & SomeOtherProtocol {
    /* ... */        
}

Also note that you can use typealias in order to shorten your function declaration.

typealias RequiredProtocols = SomeProtocol & SomeOtherProtocol

func someFunc<T: RequiredProtocols>(arg: T) {
    /* ... */   
}
Imanou Petit
  • 89,880
  • 29
  • 256
  • 218