92
votes

Given three ways of expressing the same function f(a) := a + 1:

val f1 = (a:Int) => a + 1
def f2 = (a:Int) => a + 1
def f3:(Int => Int) = a => a + 1

How do these definitions differ? The REPL does not indicate any obvious differences:

scala> f1
res38: (Int) => Int = <function1>
scala> f2
res39: (Int) => Int = <function1>
scala> f3
res40: (Int) => Int = <function1>
3
You should note that in the 2nd block above, evaluating f1 in the REPL shows the value statically bound to f1 while evaluating f2 and f3 show the result of invoking those methods. In particular, a new Function1[Int, Int] instance is produced every time either f2 or f3 is invoked, while f1 is the same Function1[Int, Int] forever.Randall Schulz
@RandallSchulz given that the val version does not require a new function instance, why would one ever use def in this case?virtualeyes
@virtualeyes The only situation that I can recall where one sees defs yielding FunctionN[...] values is in the combinator parser library. It's not very common to write methods that yield functions and virtually never would one use a def to yield many copies of a semantically / functionally unchanging function.Randall Schulz

3 Answers

122
votes

Inside a class, val is evaluated on initialization while def is evaluated only when, and every time, the function is called. In the code below you will see that x is evaluated the first time the object is used, but not again when the x member is accessed. In contrast, y is not evaluated when the object is instantiated, but is evaluated every time the member is accessed.

  class A(a: Int) {
    val x = { println("x is set to something"); a }
    def y = { println("y is set to something"); a }
  }

  // Prints: x is set to something
  val a = new A(1)

  // Prints: "1"
  println(a.x)

  // Prints: "1"                               
  println(a.x)

  // Prints: "y is set to something" and "1"                                  
  println(a.y)

  // Prints: "y is set to something" and "1"                                                                                   
  println(a.y)
112
votes

f1 is a function that takes an integer and returns an integer.

f2 is a method with zero arity that returns a function that takes an integer and returns an integer. (When you type f2 at REPL later, it becomes a call to the method f2.)

f3 is same as f2. You're just not employing type inference there.

3
votes

Executing a definition such as def x = e will not evaluate the expression e. Instead e is evaluated whenever x is used. Alternatively, Scala offers a value definition val x = e, which does evaluate the right-hand-side e as part of the evaluation of the definition. If x is then used subsequently, it is immediately replaced by the pre-computed value of e, so that the expression need not be evaluated again.

Scala By Example by Martin Odersky