Bogdan Vakulenko
Bogdan Vakulenko

Reputation: 3390

Type inference on higher-kinded types

Trying to understand what "type" actually means in scala. Here is an example:

trait A[T]
trait B[T]

val typeTest = new A[Int] with B[String]

def test [F[_],T] (t:F[T],tt:T):T= tt

test(typeTest,5)   // line #1: compiles
test(typeTest,"5") // line #2: failed

typeTest is A[Int] an B[String] at the same time. Why line #1 compiles and #2 failed? Why T is inferred only for Int?

Upvotes: 4

Views: 137

Answers (1)

Dmytro Mitin
Dmytro Mitin

Reputation: 51648

The easiest way to make this code compile is to provide a hint for compiler

test[B, String](typeTest,"5")

or

test(typeTest: B[String],"5")

It's funny that with the nightly build of Dotty vice versa

val typeTest = new A[Int] with B[String] {}
test(typeTest,"5")

compiles but

test(typeTest,5)

doesn't

[error] found:    Int(5)
[error] required: String
[error] 
[error]   test(typeTest,5)
[error]                 ^
[error] one error found

and one should provide a hint

test[A, Int](typeTest,5)

For comparison Scalac compile error was

Error:  type mismatch;
 found   : A[Int] with B[String]
 required: A[Any]
Note: Int <: Any (and A[Int] with B[String] <: A[Int]), but trait A is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)
  test(typeTest,"5")

The fact that currently Scalac and Dotty behaves (infer types) here differently means that (according to Scala specification) there is no deep difference betweeen test(typeTest,5) and test(typeTest,"5") cases. It's just imperfectness of type inference algorithms used by different compilers.

By the way, as follows from Scalac compile error message, one more option to help compilers to infer correct types is to make a trait covariant:

trait A[+T]
trait B[T]
val typeTest = new A[Int] with B[String]  
test(typeTest,5) 
test(typeTest,"5") 

for Scalac and

trait A[+T]
trait B[+T]
val typeTest = new A[Int] with B[String] {}
test(typeTest,5)
test(typeTest,"5")

for Dotty.

Upvotes: 3

Related Questions