Swift 4.1 has been out for a month, so I’m late to the party with this, but I wanted to point out what a significant step forward this release is for Swift.
Conditional conformance
Even if you never write a conditional protocol conformance yourself, having a more powerful type system is a huge deal for the standard library and other libraries. Users of these libraries don’t have to know or care about conditional conformance — for them, it simply means less frustration because more things that inexplicably didn’t work before now work as expected.
For example, you can now assert that two sets are equal in a unit test:
let intersection = Set(5...15).intersection(0..<10)
XCTAssertEqual(intersection, Set(5..<10))
This is how it always should have been. In fact, this stuff is so fundamental that in a few months we’ll probably wonder how we could get any work done in a language which didn’t support the most basic things.
Recursive constraints on associated types
The same goes for the second new generics feature, recursive constraints on associated types. Of course the subsequence of a Sequence
should itself be a Sequence
(and have the same element type). But until now, this constraint could not be expressed in the type system.
For example, this simple method for dropping the first and last element of a sequence wouldn’t compile in Swift 4.0:
extension Sequence {
func dropFirstAndLast() -> SubSequence {
// error: Value of type 'Self.SubSequence' has no member 'dropLast'
return dropFirst().dropLast()
}
}
Only when you explicitly constrain the extension to sequences whose subsequence is also a sequence and whose subsequence’s subsequence type is the subsequence type (another thing which is also valid for all sequences, but the compiler didn’t know that) is the compiler satisfied:
extension Sequence
where SubSequence: Sequence, SubSequence == SubSequence.SubSequence
{
func dropFirstAndLast() -> SubSequence {
return dropFirst().dropLast()
}
}
As of Swift 4.1, the definition of the Sequence
protocol in the standard library already includes these constraints (and others), so the first version compiles just fine.
Again, this is how it should have been all along.
The Collection
documentation is finally complete
Incidentally, the recursive constraints implementation also improves how the Swift documentation works in Xcode and on Apple’s website. If you ever (unsuccessfully) tried to find the documentation for Collection
’s associated Index
type or the index(after:)
method in the Swift 4.0 days, you can rejoice now.
The reason these and others were missing was that they were defined on the semi-private _Indexable
protocol (a crutch the standard library used to work around the missing recursive constraints) and Apple chose to hide underscored members from the documentation. In Swift 4.1, _Indexable
is gone because it’s no longer needed. Its requirements have been merged into Collection
.
IndexDistance
is gone
Taken together with a third change — the associated IndexDistance
type has been removed from Collection
— Swift 4.1 massively simplifies the writing of generic collection algorithms.
Up until Swift 4.0, extending Sequence
or Collection
with a new algorithm was too often an exercise in frustration. Deciphering the compiler’s error messages and adding the right missing constraints required a lot of knowledge of the generics system’s limitations.
With Swift 4.1, most extensions should now be a lot more straightforward to write. If you’ve added your own collection algorithms directly on Array
until now in order to not have to deal with Collection
, I encourage you to try again. Even better, if you have a collection algorithm that you think is universally useful, pitch it on the Swift forums for inclusion in the standard library!
Wrap-up
Swift’s generics system makes a big step forward with Swift 4.1. That doesn’t mean it’s finished though. In fact, there’s at least one more pesky error that I’d love to never see again:
‘X’ can only be used as a generic constraint because it has Self or associated type requirements
The associated generics feature is called generalized existentials.
Doug Gregor and Ben Cohen on Swift Unwrapped
This post is more or less a rehash of things said by Swift team members Doug Gregor and Ben Cohen on the Swift Unwrapped podcast. Doug and Ben were guests on the podcast for two episodes in March 2018 and discussed Swift 4.1. It’s a great conversation and you should listen to it: part 1, part 2 (50 minutes in total).
I leave you with a quote from Ben (paraphrased):
With Swift 4.1 the generics system has reached its first important plateau. A lot of the generics features that have been anticipated since the very beginning of Swift are now coming into the language. And that’s been really important for the standard library because a lot of the standard library has been designed with these features in mind from the very beginning.