92

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>
Coder Guy
  • 1,843
  • 1
  • 15
  • 21
qrest
  • 2,427
  • 1
  • 20
  • 26
  • 11
    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 Sep 05 '10 at 19:12
  • @RandallSchulz given that the val version does not require a new function instance, why would one ever use def in this case? – virtualeyes Jun 01 '12 at 14:04
  • 2
    @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 Jun 05 '12 at 00:18

3 Answers3

122

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)
karmakaze
  • 34,689
  • 1
  • 30
  • 32
Jack
  • 16,506
  • 19
  • 100
  • 167
  • @JacobusR is this true only inside a class? – Andrew Cassidy Aug 26 '14 at 16:58
  • for example: scala> var b = 5 b: Int = 5 scala> val a: (Int => Int) = x => x + b a: Int => Int = scala> a(5) res48: Int = 10 scala> b = 6 b: Int = 6 scala> a(5) res49: Int = 11 I was expecting a(5) to return 10 and the value of b to have been inlined – Andrew Cassidy Aug 26 '14 at 16:59
  • @AndrewCassidy the function `a` is immutable and evaluated at initialisation, but `b` remains a mutable value. So the reference to `b` is set during initialisation, but the value stored by `b` remains mutable. For fun you could now create a new `val b = 123`. After this your `a(5)` will always give 11, since the `b` is now a completely new value. – Jack Aug 28 '14 at 05:57
  • @JacobusR thanks... this makes sense. This coincides with the definition of "lexical scope" since the function a carries a reference to original "var b". I guess what made me confused is that say: var b = 5; val c = b; b = 6; acts differently. I guess I shouldn't expect a function definition which carries around references to the original "lexical" scope to behave the same way as an Int. – Andrew Cassidy Aug 28 '14 at 13:49
112

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.

missingfaktor
  • 90,905
  • 62
  • 285
  • 365
3

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

Alexander
  • 71
  • 1
  • 1
  • 4