Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different type inference for `def` and `val` in Scala

I observed a difference in Scala's type inference when applied to def and val.

Using def, I can define an abstract nullary method const returning some value of type Int => Int. When implementing const with a function literal, I need not supply a parameter type, as it can be inferred by the compiler:

trait D {
  def const: Int => Int
}
object D extends D {
  def const = i => i + 1
}

This is fine. (On the downside, a new function instance is being created for every access to D.const.)

Now consider an analogous construction using val:

trait V {
  val const: Int => Int
}
object V extends V {
  val const = i => i + 1
}

This will not compile, failing with

error: missing parameter type
   val const = i => i + 1
               ^

Why?

like image 575
knuton Avatar asked May 24 '12 13:05

knuton


People also ask

What is type inference in Scala?

The Scala compiler can infer the types of expressions automatically from contextual information. Therefore, we need not declare the types explicitly. This feature is commonly referred to as type inference. It helps reduce the verbosity of our code, making it more concise and readable.

What are different types of Scala variables?

In Scala there are two types of variables: Mutable Variables. Immutable Variables.

What is inferred datatype?

Type inference is the ability to automatically deduce, either partially or fully, the type of an expression at compile time. The compiler is often able to infer the type of a variable or the type signature of a function, without explicit type annotations having been given.

What are type parameters in Scala?

Methods in Scala can be parameterized by type as well as by value. The syntax is similar to that of generic classes. Type parameters are enclosed in square brackets, while value parameters are enclosed in parentheses.


2 Answers

If you build this code with the option -Xprint all , you will see that :

abstract trait V extends scala.AnyRef {   
<stable> <accessor> def const: Int => Int
};

final object V extends java.lang.Object with V with ScalaObject {

def this(): object V = {
  V.super.this();
  ()
};

private[this] val const: <error> => <error> = ((i: <error>) => i.+(1));
<stable> <accessor> def const: <error> => <error> = V.this.const
}

So the error occurs at the creation of private val and accessor. th compilator try to evaluate the value affected to the val const before creating the accessor def const.

if you look to the val const defined in trait, you see that the creation of private val was disabled because it's only a definition for the def const accessor.

I think the inference type with previous definition ( in trait or superclass) occurred only when he try to create the accessor, not for evaluate a value.

And for the last def const , the type is only based on the private[this] val const type : error => error

like image 89
fp4me Avatar answered Sep 22 '22 00:09

fp4me


As of Scala 2.9.1, this is “as speced”. Citing Martin Odersky from SI-2742:

For methods, return types in inherited abstract methods are taken as expected type of the right hand side. For values there is no such rule. So this would be a spec enhancement request, as I see it.

The ticket is low priority and has remained unchanged since its first discussion in late 2009, so it seems unlikely to change anytime soon.

like image 27
knuton Avatar answered Sep 24 '22 00:09

knuton