Matt Fenwick Matt Fenwick - 4 months ago 23
Swift Question

What is the cause of this type error?

Two questions:

  1. Why does this code fail to compile? I believe (but am not 100% sure, I may have made a mistake) that it's type-correct.

  2. What does the error message mean? I'm confused why the expected argument type is
    _ -> _
    (or maybe I just don't know what it means by
    _ -> _
    in this case). The goal of this question is to learn how to correctly diagnosis this error message, should I run into it again in the future.

The code:

This code fails to compile with the error message "Cannot convert value of type 'A -> B' to expected argument type '_ -> _':

class ZipList<A> {
let xs: [A]
init(xs: [A]) {
self.xs = xs
func map<B>(f: A -> B) -> ZipList<B> {
return ZipList(xs:

enter image description here

Additional information:

At first, I assumed the problem was with type inference, so I tried writing out the types explicitly, but that also failed:

enter image description here

enter image description here

However, this compiles just fine (the only difference from my original
version is the
passed to the

func map4<B>(f: A -> B) -> ZipList<B> {
return ZipList<B>(xs:


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).

Although why the compiler ignores the explicit type annotation of ZipList<B> for the return type of the function, I can't say. In any case, 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() 

Therefore 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:

This forces the generic parameter to be of type B, therefore preventing Swift from trying to (incorrectly) infer 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.