241

What is the difference between:

def even: Int => Boolean = _ % 2 == 0

and

val even: Int => Boolean = _ % 2 == 0

Both can be called like even(10).

Amir Karimi
  • 5,401
  • 4
  • 32
  • 51
  • Hi, what does `Int => Boolean` means? I think the define syntax is `def foo(bar: Baz): Bin = expr` – Ziu Sep 20 '18 at 02:51
  • @Ziu that means that the function 'even' receives an Int as an argument and returns a Boolean as a value type. So you can call 'even(3)' which evaluates to Boolean 'false' – Denys Lobur Oct 07 '18 at 12:44
  • @DenysLobur thanks for your reply! Any reference about this syntax? – Ziu Oct 07 '18 at 14:02
  • @Ziu I basically found it out from Odersky's Coursera course - https://www.coursera.org/learn/progfun1. By the time you finish it, you'll understand what 'Type => Type' means – Denys Lobur Oct 08 '18 at 12:13

9 Answers9

356

Method def even evaluates on call and creates new function every time (new instance of Function1).

def even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = false

val even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = true

With def you can get new function on every call:

val test: () => Int = {
  val r = util.Random.nextInt
  () => r
}

test()
// Int = -1049057402
test()
// Int = -1049057402 - same result

def test: () => Int = {
  val r = util.Random.nextInt
  () => r
}

test()
// Int = -240885810
test()
// Int = -1002157461 - new result

val evaluates when defined, def - when called:

scala> val even: Int => Boolean = ???
scala.NotImplementedError: an implementation is missing

scala> def even: Int => Boolean = ???
even: Int => Boolean

scala> even
scala.NotImplementedError: an implementation is missing

Note that there is a third option: lazy val.

It evaluates when called the first time:

scala> lazy val even: Int => Boolean = ???
even: Int => Boolean = <lazy>

scala> even
scala.NotImplementedError: an implementation is missing

But returns the same result (in this case same instance of FunctionN) every time:

lazy val even: Int => Boolean = _ % 2 == 0
even eq even
//Boolean = true

lazy val test: () => Int = {
  val r = util.Random.nextInt
  () => r
}

test()
// Int = -1068569869
test()
// Int = -1068569869 - same result

Performance

val evaluates when defined.

def evaluates on every call, so performance could be worse than val for multiple calls. You'll get the same performance with a single call. And with no calls you'll get no overhead from def, so you can define it even if you will not use it in some branches.

With a lazy val you'll get a lazy evaluation: you can define it even if you will not use it in some branches, and it evaluates once or never, but you'll get a little overhead from double check locking on every access to your lazy val.

As @SargeBorsch noted you could define method, and this is the fastest option:

def even(i: Int): Boolean = i % 2 == 0

But if you need a function (not method) for function composition or for higher order functions (like filter(even)) compiler will generate a function from your method every time you are using it as function, so performance could be slightly worse than with val.

With java 8+ lambda optimisations converting method to function is a cheap operation.

senia
  • 37,745
  • 4
  • 88
  • 129
  • Would you please compare them regarding the performance? Isn't it important to evaluate the function each time `even` is called. – Amir Karimi Sep 19 '13 at 06:23
  • 2
    `def` can be used to define a method, and this is fastest option. @A.Karimi – Display Name Sep 19 '13 at 06:35
  • 3
    For fun: on 2.12, `even eq even`. – som-snytt Jul 10 '16 at 03:36
  • Is there a concept of inline functions like in c++? I am coming from c++ world, so pardon my ignorance. – animageofmine Nov 27 '17 at 02:50
  • 2
    @animageofmine Scala compiler can try to inline methods. There is [`@inline` attribute](https://www.scala-lang.org/api/current/scala/inline.html) for this. But it can't inline functions because function call is a call to virtual `apply` method of a function object. JVM might devirtualise and inline such calls in some situations, but not in general. – senia Nov 27 '17 at 06:02
  • Am I understanding correctly that the syntax `def even(i: Int): Boolean =` produces a different result than `def even: Int => Boolean =` ? That is to say, the double-arrow notation is NOT just syntactic sugar, but actually means something different to the compiler? – bjmc Nov 03 '18 at 14:20
  • @bjmc: `def even: Int => Boolean` means `def even: Function2[Int, Boolean]`. It's almost like `def even(): Function2[Int, Boolean]`, but without empty argument list (0 argument lists vs 1 empty argument list). – senia Nov 04 '18 at 16:26
  • @senia : def defFunc : Int => Int = _ + 1. defFunc eq defFunc gives true. I tried this in scala repl – Ashwin Dec 27 '18 at 11:09
  • @Ashwin, jvm implementation details. Try ```def defFunc: Int => Int = { val i = uril.Random.nextInt; _ + i }``` – senia Jan 10 '19 at 08:51
  • I think this article gives a better answer of the subtle differences: https://alvinalexander.com/scala/fp-book-diffs-val-def-scala-functions – Nigel Eke Jan 31 '20 at 10:32
  • Actaully from your example I see `even eq even == true` in my scala shell – Kanagavelu Sugumar Feb 15 '22 at 10:53
  • @KanagaveluSugumar it's a java 8 optimization. For some lambdas it can use the same object for multiple method calls. See next example with `Random` - eq returns false on any jvm version. – senia Mar 17 '22 at 18:11
  • This is a great answer! I like the examples you provide to differentiate them – Kaushik Apr 04 '23 at 17:39
  • 1
    @Kaushik the first example is broken due to java 8+ optimisation (`eq` is true in both cases). I can fix it, but it will make the code more difficult. – senia Apr 05 '23 at 18:40
24

Consider this:

scala> def even: (Int => Boolean) = {
             println("def"); 
             (x => x % 2 == 0)
       }
even: Int => Boolean

scala> val even2: (Int => Boolean) = {
             println("val");
             (x => x % 2 == 0)
       }
val //gets printed while declaration. line-4
even2: Int => Boolean = <function1>

scala> even(1)
def
res9: Boolean = false

scala> even2(1)
res10: Boolean = false

Do you see the difference? In short:

def: For every call to even, it calls the body of the even method again. But with even2 i.e. val, the function is initialized only once while declaration (and hence it prints val at line 4 and never again) and the same output is used each time it accessed. For example try doing this:

scala> import scala.util.Random
import scala.util.Random

scala> val x = { Random.nextInt }
x: Int = -1307706866

scala> x
res0: Int = -1307706866

scala> x
res1: Int = -1307706866

When x is initialized, the value returned by Random.nextInt is set as the final value of x. Next time x is used again, it will always return the same value.

You can also lazily initialize x. i.e. first time it is used it is initialized and not while declaration. For example:

scala> lazy val y = { Random.nextInt }
y: Int = <lazy>

scala> y
res4: Int = 323930673

scala> y
res5: Int = 323930673
Jatin
  • 31,116
  • 15
  • 98
  • 163
  • 7
    I think your explanation may imply something you don't intend. Try calling `even2` twice, once with `1` and once with `2`. You will get different answers in each call. So, while the `println` is not executed in subsequent calls you don't get the same *result* from different calls to `even2`. As to why the `println` is not executed again, that is a different question. – melston May 17 '15 at 14:47
  • 1
    that is actually very interesting. It is like in the case of val i.e. even2, the val is evaluated to a parameterized value. so yes with a val you the evaluation of the function, its value. The println is not part of the evaluated value. It is part of the evaluation but not the evaluated value. The trick here is that the evaluated value is actually a parametarized value, that depend of some input. smart thing – MaatDeamon Jun 20 '15 at 19:00
  • 1
    @melston exactly! that's what I understood, so why doesn't the println get executed again while the output changed ? – a.u.r Jun 28 '15 at 16:21
  • 1
    @a.u.r what is returned by even2 is actually a function (the parenthesized expression at the end of the definition of even2). That function is actually called with the parameter you pass to even2 each time you invoke it. – melston Jul 01 '15 at 17:55
6

See this:

  var x = 2 // using var as I need to change it to 3 later
  val sq = x*x // evaluates right now
  x = 3 // no effect! sq is already evaluated
  println(sq)

Surprisingly, this will print 4 and not 9! val (even var) is evaluated immediately and assigned.
Now change val to def.. it will print 9! Def is a function call.. it will evaluate each time it is called.

Apurva Singh
  • 4,534
  • 4
  • 33
  • 42
1

val i.e. "sq" is by Scala definition is fixed. It is evaluated right at the time of declaration, you can't change later. In other examples, where even2 also val, but it declared with function signature i.e. "(Int => Boolean)", so it is not Int type. It is a function and it's value is set by following expression

   {
         println("val");
         (x => x % 2 == 0)
   }

As per Scala val property, you can't assign another function to even2, same rule as sq.

About why calling eval2 val function not printing "val" again and again ?

Orig code:

val even2: (Int => Boolean) = {
             println("val");
             (x => x % 2 == 0)
       }

We know, in Scala last statement of above kind of expression (inside { .. }) is actually return to the left hand side. So you end up setting even2 to "x => x % 2 == 0" function, which matches with the type you declared for even2 val type i.e. (Int => Boolean), so compiler is happy. Now even2 only points to "(x => x % 2 == 0)" function (not any other statement before i.e. println("val") etc. Invoking event2 with different parameters will actually invoke "(x => x % 2 == 0)" code, as only that is saved with event2.

scala> even2(2)
res7: Boolean = true

scala> even2(3)
res8: Boolean = false

Just to clarify this more, following is different version of the code.

scala> val even2: (Int => Boolean) = {
     |              println("val");
     |              (x => { 
     |               println("inside final fn")
     |               x % 2 == 0
     |             })
     |        }

What will happen ? here we see "inside final fn" printed again and again, when you call even2().

scala> even2(3)
inside final fn
res9: Boolean = false

scala> even2(2)
inside final fn
res10: Boolean = true

scala> 
Sandi
  • 11
  • 2
1

Executing a definition such as def x = e will not evaluate the expression e. In- stead e is evaluated whenever x is invoked.

Alternatively, Scala offers a value definition val x = e,which does evaluate the right-hand-side 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.

Gaurav Khare
  • 2,203
  • 4
  • 25
  • 23
0

also, Val is a by value evaluation. Which means the right-hand side expression is evaluated during definition. Where Def is by name evaluation. It will not evaluate until it's used.

0

In addition to the above helpful replies, my findings are:

def test1: Int => Int = {
x => x
}
--test1: test1[] => Int => Int

def test2(): Int => Int = {
x => x+1
}
--test2: test2[]() => Int => Int

def test3(): Int = 4
--test3: test3[]() => Int

The above shows that “def” is a method (with zero argument parameters) that returns another function "Int => Int” when invoked.

The conversion of methods to functions is well explained here: https://tpolecat.github.io/2014/06/09/methods-functions.html

jkdev
  • 11,360
  • 15
  • 54
  • 77
prateek
  • 89
  • 1
  • 6
0

In REPL,

scala> def even: Int => Boolean = { _% 2 == 0 }
even: Int => Boolean

scala> val even: Int => Boolean = { _% 2 == 0 }
even: Int => Boolean = $$Lambda$1157/1017502292@57a0aeb8

def means call-by-name, evaluated on demand

val means call-by-value, evaluated while initialization

GraceMeng
  • 949
  • 8
  • 6
  • With a question this old, and with so many answers already submitted, it is often helpful to explain how your answer differs from, or adds to, the information provided in the existing answers. – jwvh Jan 11 '19 at 23:50
0

Note: There are different types of functions in Scala: abstract, concrete, anonymous, high order, pure, impure etc...

Explaining val function:

A val function in Scala is a complete object. There are traits in Scala to represent functions with various numbers of arguments: Function0, Function1, Function2, etc. As an instance of a class that implements one of these traits, a function object has methods. One of these methods is the apply method, which contains the code that implements the body of the function.

When we create a variable whose value is a function object and we then reference that variable followed by parentheses, that gets converted into a call to the apply method of the function object.

Explaining Method i.e def:

Methods in Scala are not values, but functions are.

A Scala method, as in Java, is a part of a class. It has a name, a signature, optionally some annotations, and some bytecode.

The implementation of a method is an ordered sequence of statements that produces a value that must be compatible with its return type.

initvik
  • 91
  • 1
  • 5