GO FURTHER, FASTER: Try the Swift Career Accelerator today! >>

Conditional conformances

Available from Swift 4.1

Paul Hudson      @twostraws

Swift 4.1 implements SE-0143, which introduced proposed conditional conformances into the language. This allows types to conform to a protocol only when certain conditions are met.

To demonstrate conditional conformances, let's create a Purchaseable protocol that we can use to buy things:

protocol Purchaseable {
   func buy()
}

We can now define a Book struct that conforms to the protocol, and prints a message when a book is bought:

struct Book: Purchaseable {
   func buy() {
      print("You bought a book")
   }
}

So far this is easy enough, but let's take it one step further: what if the user has a basket full of books, and wants to buy them all? We could loop over all books in the array by hand, calling buy() on each one. But a better approach is to write an extension on Array to make it conform to Purchaseable, then give it a buy() method that in turn calls buy() on each of its elements.

This is where conditional conformances come in: if we tried to extend all arrays, we'd be adding functionality where it wouldn't make sense – we'd be adding buy() to arrays of strings, for example, even though those strings don't have a buy() method we can call.

Swift 4.1 lets us make arrays conform to Purchaseable only if their elements also conform to Purchaseable, like this:

extension Array: Purchaseable where Element: Purchaseable {
   func buy() {
      for item in self {
         item.buy()
      }
   }
}

As you can see, conditional conformances let us constrain the way our extensions are applied more precisely than was possible before.

Conditional conformances also make large parts of Swift code easier and safer, even if you don't do any extra work yourself. For example, this code creates two arrays of optional strings and checks whether they are equal:

var left: [String?] = ["Andrew", "Lizzie", "Sophie"]
var right: [String?] = ["Charlotte", "Paul", "John"]
left == right

That might seem trivial, but that code wouldn't even compile in Swift 4.0 – both String and [String] were equatable, but [String?] was not.

The introduction of conditional conformance in Swift 4.1 means that it’s now possible to add protocol conformance to a type as long as it satisfies a condition. In this case, if the elements of the array are equatable, that means the whole thing is equatable. So, the above code now compiles in Swift 4.1

Conditional conformance has been extended to the Codable protocol in a way that will definitely make things safer. For example:

struct Person {
   var name = "Taylor"
}

var people = [Person()]
var encoder = JSONEncoder()
// try encoder.encode(people)

If you uncomment the encoder.encode(people) line, Swift will refuse to build your code because you're trying to encode a struct that doesn't conform to Codable. However, that code compiled cleanly with Swift 4.0, then threw a fatal error at runtime because Person doesn’t conform to Codable.

Obviously no one wants a fatal error at runtime, because it means your app crashes. Fortunately, Swift 4.1 cleans this up using conditional conformances: Optional, Array, Dictionary, and Set now only conform to Codable if their contents also conform to Codable, so the above code will refuse to compile.

Hacking with Swift is sponsored by Essential Developer.

SPONSORED Transform your career with the iOS Lead Essentials. This Black Friday, unlock over 40 hours of expert training, mentorship, and community support to secure your place among the best devs. Click for early access to this limited offer and a free crash course.

Save your spot

Sponsor Hacking with Swift and reach the world's largest Swift community!

Other changes in Swift 4.1…

Download all Swift 4.1 changes as a playground Link to Swift 4.1 changes

Browse changes in all Swift versions

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.