The problem is that when you don't explicitly supply the generic parameter type of ZipList
when you refer to it, the compiler will try and infer it for you – which it doesn't always get correct.
As you're already inside a ZipList<A>
class, the compiler will try and infer ZipList
to be ZipList<A>
when you omit the generic parameter (see this question for more info about this behaviour).
Therefore it's now expecting an input of [A]
in the ZipList(xs:_)
initialiser, meaning that the map function is inferred to be A -> A
, which you're trying to pass A -> B
to, causing the type mismatch (this is why f
is highlighted as the problem in your error).
If you simplify down your example to just calling init()
on your ZipList
without providing an argument, you'll see a more helpful error message:
class ZipList<A> {
init() {}
func map<B>() -> ZipList<B> {
// error: Cannot convert return expression of type 'ZipList<A>' to 'ZipList<B>'
return ZipList()
}
}
The fact that the compiler completely ignores the explicit type annotation of the return for the map()
method is a bug and is tracked by SR-1789. The cause, as described by Jordan Rose in the comments of the report is that:
It seems to be a case of us eagerly assuming the parameters are the same as for self
. (That's usually a feature, but not when it gets in the way of other inference.)
The solution, as you've already found, is to explicitly state the generic parameter type of ZipList
when you create a new instance:
return ZipList<B>(xs: xs.map(f))
This forces the generic parameter to be of type B
, therefore preventing Swift from incorrectly inferring it, allowing the map
function to resolve.
As for what the error message "Cannot convert value of type 'A -> B' to expected argument type '_ -> _" means, _
in this case simply refers to a generic type which the compiler cannot resolve (not a helpful error message, I know). So all the compiler is telling you is that it was expecting a function that takes an input of an unknown type, and returns that same type.
It often helps when diagnosing these kind of error messages to split the expression up into multiple sub-expressions and inspect the types for each those to try and find the mis-match. It can also help to begin simplifying the example down (like using init()
instead of init(xs:[A])
in your map
method), until you run into a more helpful error message.