New features in Swift 4.2
Yesterday, Apple officially released the latest version of Swift programming language - Swift 4.2. It is a major release with a lot of improvements that include faster build times and features aimed towards removing boilerplate code and improving efficiency. It is also a significant step towards ABI stability planned for Swift 5.
There were many proposals that were accepted in this release. In this blog post, I will go through the ones that I find interesting.
To be able to use a custom type in
Set or as a key in
Dictionary, it has to conform to
Hashable protocol. In Swift 4.1,
Hashable protocol looked like this:
Each custom type that implements
Hashable has to provide a
hashValue. Calculating the
hashValue is not as simple as it seems. If the algorithm is not good enough, the cost is pretty high, because it impacts the performance of
Set. That is why
Hashable protocol was redesigned in Swift 4.2:
To implement the new
Hashable protocol, we have to call the hash function on the conforming type’s properties that we want to use in hash calculation and pass in the hasher as an argument. As an example, we can implement it on
Note that there is also a generic
Hasher.combine<H>(_:) method which is completely equivalent to
Hasher.hash(into:) method and can be used in the same way.
Diagnostic directives - #warning and #error
An interesting feature implemented in this release are
#error compiler diagnostic directives. As their names already say,
#warning will cause Xcode to emit a warning when building code and
#error will cause a compile error.
#warning is very useful for marking code that is unfinished and it is a much more robust solution than marking the code with
#error can be used, for example, to notify the user that a library is not available on certain platforms:
Before Swift 4.2, there was no standard way of listing all cases in enums. What one could do is create an
allCases static property that returns a collection of all enum cases:
This solution, however, is not optimal, because if we later add another case in the enum we have to add that case to
This is where
CaseIterable protocol comes into play. Our enum only has to conform to the protocol and the
allCases property will be generated for us at compile time. Cases are ordered in order of their declaration.
Note that compiler synthesis only works for enums without associated values.
Upgrading self from a weak to strong reference
One common pattern when working with closures in Swift is capturing
self weakly to avoid retain cycles. The only mechanism for upgrading weak
self to a strong reference is to unwrap it using
if let or
guard let statements. The problem is that we have to use a variable with an arbitrary name like
strongSelf because we can’t use
self for variable’s name. This introduces a lot of inconsistencies in the codebase.
Now, as of Swift 4.2, we can use
self for naming the variable used for unwrapping like this:
I’ve covered some of the features that were introduced in Swift 4.2 that were interesting to me. There are a lot of changes that I didn’t cover. You can read more about them on Apple’s official Swift blog.