Multiple Type Constraints in Swift

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>

Answers


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.


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
    }
    

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


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) {
    /* ... */   
}

Need Your Help

Internet Explorer 10 ignores width & height on images

html css image internet-explorer-10

I have a website in which Internet Explorer 10 is completely ignoring the explicitly set width and height attributes in favour of the actual image size.

REST API - why use PUT DELETE POST GET?

php json api rest soap

So, I was looking through some articles on creating REST API's.