Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the cause of this type error?

Tags:

types

swift

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: self.xs.map(f))
    }
}

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 map version is the <B> passed to the ZipList initializer):

func map4<B>(f: A -> B) -> ZipList<B> {
    return ZipList<B>(xs: self.xs.map(f))
}
like image 407
Matt Fenwick Avatar asked Jun 16 '16 14:06

Matt Fenwick


People also ask

What causes a type error?

Type 1 error, in statistical hypothesis testing, is the error caused by rejecting a null hypothesis when it is true. Type 1 error is caused when the hypothesis that should have been accepted is rejected. Type I error is denoted by α (alpha) known as an error, also called the level of significance of the test.

What causes Type 1 and Type 2 error?

A type I error (false-positive) occurs if an investigator rejects a null hypothesis that is actually true in the population; a type II error (false-negative) occurs if the investigator fails to reject a null hypothesis that is actually false in the population.

What causes a type two error?

Type II error is mainly caused by the statistical power of a test being low. A Type II error will occur if the statistical test is not powerful enough. The size of the sample can also lead to a Type I error because the outcome of the test will be affected.

What is Type 1 and Type 2 error example?

Type I error (false positive): the test result says you have coronavirus, but you actually don't. Type II error (false negative): the test result says you don't have coronavirus, but you actually do.


1 Answers

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.

like image 131
Hamish Avatar answered Oct 18 '22 10:10

Hamish