NADocumentPicker returns a Future<T, E: ErrorType> with the type:

Future<NSURL, AnyError>

What is AnyError in the above code? AnyError provides a unified concrete error type for a Future . A unified error type is necessary when composing futures with flatMap so, if one of the futures fails, the error can be propagated through the compositional chain.

For example:

@IBAction func pickerButtonPressed(sender: UIButton) {
    let urlFuture = NADocumentPicker.show(from: sender, parentViewController: self)
    let documentFuture = urlFuture.flatMap { url in MyDocument(url).open() }

    documentFuture.onSuccess { document in
        print("Opened document: \(document)")
    }
}

The Future returned by open() has to have an identical error type to allow the compositional chain to transform:

Future<NSURL, AnyError> /*to*/ Future<MyDocument, AnyError>
//     NSURL              to          MyDocument

It would not be possible to compose with flatMap if the transformation was:

Future<NSURL, NADocumentPickerErrors> /*to*/ Future<MyDocument, MyDocumentErrors>
// can't use flatMap to compose with incompatible ErrorTypes

The above composition is not possible even-though all error types derive from ErrorType .

Why not use ErrorType directly as Future<NSURL, ErrorType>? Unfortunately Swift does not allow protocols to be used as concrete type parameters and generates the error:

Using ‘ErrorType’ as a concrete type conforming to protocol ‘ErrorType’ is not allowed

AnyError

AnyError conforms to ErrorType and wraps any type conforming to ErrorType, allowing different error types to be treated uniformly:

public struct AnyError : ErrorType {
    public let cause:ErrorType

    public init(cause:ErrorType) {
        self.cause = cause
    }
}

Type Erasure

This pattern of using AnyError as a generic concrete error type is known “type erasure”. The Swift standard library contains a few other type erasing wrappers, for example AnySequence<T>:

AnySequence wraps any sequence with element type T, conforms to SequenceType itself, and forwards all operations to the wrapped sequence. When handling the wrapper, the specific type of the wrapped sequence is fully hidden.

AnySequence is used below to “erase” the origin of the sequence generated from a zip operation:

let sequence1 = zip("hello".characters, "world".characters)
sequence1.dynamicType // Zip2Sequence<String.CharacterView, String.CharacterView>.Type

let sequence2 = AnySequence(sequence1)
sequence2.dynamicType // AnySequence<(Character, Character)>.Type

See also