Dan Barowy
Dan Barowy

Reputation: 2270

Why doesn't the Scala compiler accept this lambda as a parameter?

Suppose I have an interface for a Thing:

abstract class Thing[A](a_thing: A) {
  def thingA = a_thing
}

and I implement that Thing as follows:

class SpecificThing(a: String) extends Thing[String](a)

Furthermore, suppose I have a function that takes a Thing and a lambda that does something to that Thing as parameters:

def doSomething[A](fn: Thing[A] => A, t: Thing[A]) : A = fn(t)

Now, let's use this stuff:

val st = new SpecificThing("hi")
val fn1: (Thing[String]) => String = (t: Thing[String]) => { t.thingA }
println(doSomething(fn1, st))

This prints hi. So far, so good. But I'm lazy, and I don't like typing so much, so I change my program to the following:

type MyThing = Thing[String]
val st = new SpecificThing("hi")
val fn2: (MyThing) => String = (t: MyThing) => { t.thingA }
println(doSomething(fn2, st))

and this also prints hi. Fabulous! The compiler can tell that a SpecificThing is both a Thing[String] and a MyThing. But what about this case?

val st = new SpecificThing("hi")
val fn3: (SpecificThing) => String = (t: SpecificThing) => { t.thingA }
println(doSomething(fn3, st))

Now I get:

Error:(14, 23) type mismatch;
 found   : SpecificThing => String
 required: Thing[?] => ?
  println(doSomething(fn3, st))
                      ^

What's going on? What's a Thing[?]?

Upvotes: 1

Views: 99

Answers (1)

lmm
lmm

Reputation: 17431

f3 isn't a Thing[String] => String, it's a SpecificThing => String. For an example of why they couldn't be compatible:

class SpecificThing2 extends Thing[String] {
  def thingB = 2.0
}
val f4: SpecificThing2 => String = {
  st: SpecificThing2 => f"%f${st.thingB / 3.0}"
}
val t = new Thing[String]("haha"){}
f4(t) // would be an error when f4 tried to access t.thingB

More formally, Function1 is contravariant in its first type parameter, Function1[-T, +R].

A Thing[?] is what it looks like; it's a Thing[X] for some unknown type X. The compiler is gamely trying to infer what the type A should be, but it can't make it work: it needs a Thing[A] => A for some (unknown-to-it) type A, and you're passing it a SpecificThing => String; that's the error.

Upvotes: 6

Related Questions