Foundation overloads the pattern matching operator ~= to enable matching against error codes in catch clauses.
catch clauses in Swift support pattern matching, using the same patterns you’d use in a case clause inside a switch or in an if case … statement. For example, to handle a file-not-found error you might write:
import Foundation
do {
let fileURL = URL(filePath: "/abc") // non-existent file
let data = try Data(contentsOf: fileURL)
} catch let error as CocoaError where error.code == .fileReadNoSuchFile {
print("File doesn't exist")
} catch {
print("Other error: \(error)")
}
This binds a value of type CocoaError to the variable error and then uses a where clause to check the specific error code.
However, if you don’t need access to the complete error instance, there’s a shorter way to write this, matching directly against the error code:
let data = try Data(contentsOf: fileURL)
- } catch let error as CocoaError where error.code == .fileReadNoSuchFile {
+ } catch CocoaError.fileReadNoSuchFile {
print("File doesn't exist")
Foundation overloads ~=
I was wondering why this shorter syntax works. Is there some special compiler magic for pattern matching against error codes of NSError instances? Turns out: no, the answer is much simpler. Foundation includes an overload for the pattern matching operator ~= that matches error values against error codes.1
The implementation looks something like this:
public func ~= (code: CocoaError.Code, error: any Error) -> Bool {
guard let error = error as? CocoaError else { return false }
return error.code == code
}
The actual code in Foundation is a little more complex because it goes through a hidden protocol named _ErrorCodeProtocol, but that’s not important. You can check out the code in the Foundation repository: Darwin version, swift-corelibs-foundation version.
This matching on error codes is available for CocoaError, URLError, POSIXError, and MachError (and possibly more types in other Apple frameworks, I haven’t checked).
-
I wrote about the
~=operator before, way back in 2015(!): Pattern matching in Swift and More pattern matching examples. ↩︎