Reputation: 23
Compiling this code
case class MyType()
object TestMe extends App {
type Fun[T] = T => Int
def myFun[T](x: T): Int = ???
def matcher[T](f: Fun[T])(p: T): Int = ???
var f = myFun[MyType] _
val p = MyType()
matcher(f)(p)
}
fails with this error:
Error:(16, 11) type mismatch;
found : ... MyType => Int
required: ... TestMe.Fun[T]
(which expands to) T => Int
matcher(f)(p)
Changing the code as shown below fixes the problem:
case class MyType()
object TestMe extends App {
type Fun[T] = T => Int
def myFun[T](x: T): Int = ???
def matcher[T](f: Fun[T])(p: T): Int = ???
var f: Fun[MyType] = myFun[MyType] // <-- Explicit type
val p = MyType()
matcher(f)(p)
}
Also changing the arguments order fixes the problem:
case class MyType()
object TestMe extends App {
type Fun[T] = T => Int
def myFun[T](x: T): Int = ???
def matcher[T](p: T)(f: Fun[T]): Int = ??? // <-- Flipping the argument, so the first argument have explicitly the parametric type
var f = myFun[MyType] _
val p = MyType()
matcher(p)(f) // <-- Calls with flipped arguments
}
My understanding (I guess due to my lack of Scala knowledge) is that 'type' is just creating type aliases, but does not look like that. Can someone explain the reason for the compilation failure?
Thanks
Upvotes: 2
Views: 237
Reputation: 149538
This is a limitation of type inference and how the typer resolves types at compile time.
In Scala, types can be infered between parameter lists (and not inside them). When you first place p
of type T
as an argument in the first parameter list, the typer can first bind T
to MyType
, and then the second parameter list for knows the f
is of Fun[MyType]
since it can infer T
:
|-- matcher(p)(f) : pt=Unit EXPRmode (site: method main in Test)
| | | | |-- matcher(p) BYVALmode-EXPRmode-FUNmode-POLYmode (silent: method main in Test)
| | | | | |-- matcher BYVALmode-EXPRmode-FUNmode-POLYmode (silent: method main in Test)
| | | | | | [adapt] [T](p: T)(f: Fun[T])Int adapted to [T](p: T)(f: Fun[T])Int
| | | | | | \-> (p: T)(f: Fun[T])Int
| | | | | |-- p BYVALmode-EXPRmode-POLYmode (silent: method main in Test)
| | | | | | \-> MyType
| | | | | solving for (T: ?T)
| | | | | \-> (f: Fun[MyType])Int
| | | | |-- f : pt=Fun[MyType] BYVALmode-EXPRmode (site: method main in Test)
| | | | | \-> MyType => Int
The other way around doesn't work, the compiler can't infer T
being MyType
from a function of type MyType => Int
(remember that functions maybe also be contravariant in their argument type):
-- matcher(f)(p) : pt=Unit EXPRmode (site: method main in Test)
| | | | |-- matcher(f) BYVALmode-EXPRmode-FUNmode-POLYmode (silent: method main in Test)
| | | | | |-- matcher BYVALmode-EXPRmode-FUNmode-POLYmode (silent: method main in Test)
| | | | | | [adapt] [T](f: Fun[T])(p: T)Int adapted to [T](f: Fun[T])(p: T)Int
| | | | | | \-> (f: Fun[T])(p: T)Int
| | | | | |-- f : pt=Fun[?] BYVALmode-EXPRmode-POLYmode (silent: method main in Test)
| | | | | | \-> MyType => Int
| | | | | solving for (T: ?T)
| | | | | [search #1] start `MyType => Int`, searching for adaptation to pt=(MyType => Int) => Fun[T] (silent: method main in Test) implicits disabled
| | | | | [search #2] start `MyType => Int`, searching for adaptation to pt=(=> MyType => Int) => Fun[T] (silent: method main in Test) implicits disabled
As you've noted, switching the parameter lists works. You can also explicitly help the compiler infer the type by stating it on the matcher
method:
matcher[MyType](f)(p)
Upvotes: 3