RickiG
RickiG

Reputation: 11390

Result type with generic Success Type

I'm switching over a project from a custom Result type to the native Swift Result type and keep running into this - or similar - error messages:

Member 'success' in 'Result<_, Error>' produces result of type 'Result<Success, Failure>', but context expects 'Result<_, Error>'

protocol DataFetcher {
    func request<T>(completion: @escaping (Result<T, Error>) -> Void )
}

struct RandomFetcher: DataFetcher {
    func request<String>(completion: @escaping (Result<String, Error>) -> Void) {
        let str = "Hello"
        completion(.success(str))
    }
}

The idea is to have make a bunch of generic Fetchers for different data extraction calls and to pass these to VC's who would have a var fetcher: DataFetcher property. The VC's know which concrete types they expect from their request. I can't use an associated type as I need to save a bunch of these in an array and I thought I could get away with just the generic implementation - but it almost seems as if the Result type being declared as a generic in the protocol, means that it won't accept when I specify it in the implementation. What am I missing?

Upvotes: 1

Views: 875

Answers (2)

vadian
vadian

Reputation: 285064

In this case an associated type is preferable

protocol DataFetcher {
    associatedtype FetchType
    func request(completion: @escaping (Result<FetchType, Error>) -> Void )
}

struct RandomFetcher: DataFetcher {
    func request(completion: @escaping (Result<String, Error>) -> Void) {
        let str = "Hello"
        completion(.success(str))
    }
}

Upvotes: 1

Rob Napier
Rob Napier

Reputation: 299355

func request<String>(completion: @escaping (Result<String, Error>) -> Void) {

This is a classic generics mistake in Swift. This does not mean "request requires T==String." This means "there is an arbitrary type called String that this function accepts." There is no relationship between this String and Swift.String.

What you're trying to do here violates the protocol. The protocol says that the caller gets to pick any T they want. You can't conform to that protocol with a restricted T.

If you want the conforming type (RandomFetcher) to get to decide the type of T, then you have to use an associatedType (that's what associatedType means).

The thing you're trying to build is pretty common, but not trivial, and requires a different way of thinking about the problem. I walk through it step-by-step in this series.

Upvotes: 4

Related Questions