Why doesn't Scala infer trait type parameters?

trait foo[F] {
  def test: F
}

class ah extends foo[(Int,Int) => Int] {
  def test = (i: Int,j: Int) => i+j
}

      

So the question is, why can't Scala, which is known to be so smart about types, can't just infer the type (Int,Int) => Int

from the type test

by asking me to specify it instead? Or is it still possible? Or maybe it is supported by some thoughts that I do not have in mind.

+3


source to share


2 answers


Your question is basically "why Scala only has local inference" or equivalently "why Scala doesn't have non-local inference". And the answer is: because the designers don't want to.

There are several reasons for this. One reason is that the most reasonable alternative to local inference is global type inference, but that is not possible in Scala: Scala has separate compilation and module type checking, so there is simply no point in time when the compiler has a global view of the entire program. In fact, Scala has dynamic code loading, which means that at compile time all the code doesn't need to exist yet! Global type inference is simply not possible in Scala. The best we could do is "output an integer unit of measure", but that is also undesirable: it would mean whether you need type annotations depending on whether you are compiling your code in multiple units or just one.

Another important reason is that type annotations on module boundaries are double-checked, sort of like storing double-entry books for types. Note that even in languages ​​with global Haskell type inference, it is highly recommended to place type annotations on module boundaries and public interfaces.



The third reason is that global type inference can sometimes lead to confusing error messages when, instead of a type checker that does not do type annotation, the inferencer type happily ponders invoking increasingly insensitive types until it finally gives up a location away from an actual error (which could just be a simple typo) to a type error that only deals with the original types on the error site. This can happen sometimes in Haskell. Scala designers value useful error messages so much that they are willing to sacrifice language features if they cannot figure out how to implement them with good error messages. (Note that even with Scala's very limited output type, you might still get "useful" messages like "expected Foo

receivedProduct with Serializable

".)

However, what Scala can do local type inference in this example is to work in the other direction and infer the parameter types of the anonymous function from the return type test

:

trait foo[F] {
  def test: F
}

class ah extends foo[(Int, Int) β‡’ Int] {
  def test = (i, j) β‡’ i + j
}

(new ah) test(2, 3) //=> 5

      

+7


source


For your example, the derivation of type parameters based on inheritance can be ambiguous:

trait A
trait B extends A

trait Foo[T] {
    val x: T
}

trait Bar extends Foo[?] {
    val x: B
}

      

The type that can be in ?

can be either A

or B

. This is a common example where Scala will not infer types that might be ambiguous.

Now you are right to notice that there are similarities between



class Foo[T](x: T)

      

and

trait Foo[T] { x: T }

      

I've seen some work, perhaps generalizing the similarities (but I can't find one right now). In theory, this could allow the type parameter to be injected based on a member. But I don't know if he can ever get to that.

+1


source







All Articles