Definition

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
/// A value that represents either a success or a failure, including an
/// associated value in each case.
@frozen public enum Result<Success, Failure> where Failure : Error {

    /// A success, storing a `Success` value.
    case success(Success)

    /// A failure, storing a `Failure` value.
    case failure(Failure)
}

Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
struct Person: Decodable {
    let name: String
    let age: Int
}

extension String: Error {}

func loadPerson(from json: String) -> Result<Person, Error> {
    guard let data = json.data(using: .utf8) else {
        return .failure("Error in encoding string using utf8.")
    }
    do {
        let person = try JSONDecoder().decode(Person.self, from: data)
        return .success(person)
    } catch {
        return .failure(error)
    }
}

let json = """
{
    "name": "Jack Reacher",
    "age": 35
}
"""

let result = loadPerson(from: json)

switch result {
case .success(let person):
    print(person.name) // Jack Reacher
case .failure(let error):
    print(error.localizedDescription)
}

Value Transformation

Its functions for transformaing associated sucess and failure values:

1
2
3
4
5
6
7
@inlinable public func map<NewSuccess>(_ transform: (Success) -> NewSuccess) -> Result<NewSuccess, Failure>

@inlinable public func mapError<NewFailure>(_ transform: (Failure) -> NewFailure) -> Result<Success, NewFailure> where NewFailure : Error

@inlinable public func flatMap<NewSuccess>(_ transform: (Success) -> Result<NewSuccess, Failure>) -> Result<NewSuccess, Failure>

@inlinable public func flatMapError<NewFailure>(_ transform: (Failure) -> Result<Success, NewFailure>) -> Result<Success, NewFailure> where NewFailure : Error

Conversion between Result and throwing expression

Result ➡️ throwing expression

The get() function of Result enables us to convert a Result value to a throwing expression.

1
@inlinable public func get() throws -> Success
1
let optionalPerson = try? loadPerson(from: json).get()

Throwing expression ➡️ Result

Below is a throwing version of function loadPerson(from:):

1
2
3
4
5
6
7
func throwingLoadPerson(from json: String) throws -> Person {
    guard let data = json.data(using: .utf8) else {
        throw "Error in encoding string using utf8."
    }
    let person = try JSONDecoder().decode(Person.self, from: data)
    return person
}

Wrap the throwing call as Result:

1
let personResult = Result { try throwingLoadPerson(from: json) }

The conversion is made possible by this function:

1
2
3
4
5
6
7
8
extension Result where Failure == Error {

    /// Creates a new result by evaluating a throwing closure, capturing the
    /// returned value as a success, or any thrown error as a failure.
    ///
    /// - Parameter body: A throwing closure to evaluate.
    public init(catching body: () throws -> Success)
}

Use with Never

Since Never conforms to Error protocol, it can be used as the failure value type in Result.

1
2
3
4
5
6
7
8
let result: Result<Int, Never> = .success(100)

switch result {
case .success(let number):
    print(number)
//case .failure(_): // compiler won't yell at you without the failure case.
//    break
}