I'm attempt to create an extension to a PromiseKit Promise to transform a Promise<DataResponse<Request.Response> to a Promise<Request.Response>:
extension Promise {
func responseValue<Request: RawRequestEncodable & Requestable>() -> Promise<Request.Response>
where T == DataResponse<Request.Response> {
return then { (response) in
Promise<Request.Response> { (seal) in
response.result.withValue { seal.fulfill($0) }
.withError { seal.reject($0) }
}
}
}
}
It compiles when I incorrectly use Promise<Request> as the return type, but fails with a "Generic parameter Request is not used in function signature" error when I try to return Promise<Request.Response>. This seems incorrect. Is this a compiler bug or are my types incorrect?
I think there's not enough type information, since we can't manually specify generic parameters when calling a function. If this function were to compile, how would you provide enough information for it to know what Request is? The calling context would only be enough to infer Request.Response, and the compiler can't work backward from there.
I suppose I'm a bit confused then. Response is an associatedtype of one of the protocols used to define Request. Doesn't that mean that the type of Response is dependent on Request?
@Lantua Your suggestion works, thanks! I suppose I was trying to be too particular on the generic requirements. It doesn't really matter where the Promise<DataResponse<Response>> comes from, it can always be turned into a Promise<Response>.
My final version is just this:
extension Promise {
func responseValue<Response>() -> Promise<Response>
where T == DataResponse<Response> {
return then { (response) in
Promise<Response> { (seal) in
response.result.withValue { seal.fulfill($0) }
.withError { seal.reject($0) }
}
}
}
}
While I'm here, @Max_Howell1, is this a good way to accomplish this?
While I donât think of generics in term of dependencies, Iâd say itâs the other way around. Int works fine on its own but you canât work with Array unless you supply itâs associatedType (e.g. Array<Int>).
When specifying generics I tend to ask what other types would benefit from the function/instance I just wrote, then try to fine a placeholder type that encompasses all those types.
Also, whenever I see == in genericâs where clause, I have a sneaky suspicion that one can remove the placeholder type, since only one type will satisfy that requirement.
While I donât know what name is used for DataResponseâs placeholder type, itâd go like this:
Seems like a code smell to me that you can then off something that has intrinsic âResultinessâ.
Hard to know what to suggest without seeing the code that might produce the DataResponse<Response> object. But usually in PromiseKit itself we would create an extension on the thing that produces that type and have it return a Promise, which here would be Promise<Response>.