Abusing Swift’s Result Type
A tale about when the Result type shouldn’t be used.
When the Result
type was added to Swift’s standard library a few years ago, this simple change affected how we treat completion-based asynchronous methods enormously. Judge for yourself: Clumsy and ambiguous completion handlers like this sank into oblivion:
func getData(_ completionHandler: (_ data: Data?, _ error: Error?) -> Void)
In case someone doesn’t fully understand the ugliness of the method presented above, no, the problem is not (only) in multiple arguments of the closure. The main issue is the arguments’ nullability: Every time, you have to check both of them in order to determine whether the call succeeded or failed. What if both of them are
nil?
Or even worse, both are notnil
?
Result
solves the problem rather elegantly:
func getData(_ completionHandler: (_ result: Result<Data, Error>) -> Void)
So, instead of this mess:
getData { data, error in
if let error {
// Handle the error.
}
if let data {
// Use the data.
}
// Handle the probably impossible case of both error and data being nil.
}
We have this one:
getData { result in
switch result {
case…