Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between def and val in Scala

Tags:

scala

loop is defined as below:

 def loop : Boolean = loop

When x is defined as: def x = loop then "x: Boolean" is shown in console.

and

When x is defined as: val x = loop then it goes to infinite loop

I know def is using call by-name and val is using call by-value. Even though this point about loop defined above is not much clear.

like image 247
Styne.John. Avatar asked Mar 07 '18 04:03

Styne.John.


People also ask

What is val in Scala?

a new value can be defined with keyword val. eg. val x: Int = 5. Here type is optional as scala can infer it from the assigned value.

What does def mean in Scala?

def is the keyword you use to define a method, the method name is double , and the input parameter a has the type Int , which is Scala's integer data type. The body of the function is shown on the right side, and in this example it simply doubles the value of the input parameter a : def double(a: Int) = a * 2 -----

What is the difference between method and function in Scala?

Difference between Scala Functions & Methods: Function is a object which can be stored in a variable. But a method always belongs to a class which has a name, signature bytecode etc. Basically, you can say a method is a function which is a member of some object.

How do you call val in Scala?

The multiple assignments can be possible in Scala in one line by using 'val' keyword with variable name separated by commas and the "=" sign with the value for the variable.


2 Answers

def doesn't evaluate the right-hand side of the assignment. Just like

def f(x : Int) = x + 2

doesn't (in this case logically can't) evaluate f of anything, just defines what the function f, means, neither def loop : Boolean = loop nor def x = loop evaluate anything. You are just defining a function to be executed at some other point.

But vals do require the right-hand side of the assignment to be evaluated. So val x = loop tries to execute the expression on the right-hand side. Trying to evaluate loop never terminates, though, since loop is an infinite loop.

like image 103
Steve Waldman Avatar answered Oct 01 '22 07:10

Steve Waldman


The call-by-name or call-by-value distinction seems less useful in this case, because neither your x, nor your loop take any arguments.

But there are two other ways in which val and def differ.

First distinction is: eager vs. lazy.

  • The right hand side of val is evaluated eagerly, as soon as the val is defined.
  • The right hand side of def is evaluated lazily, as soon as the def is accessed.

For example:

def x = { println("x is evaluated"); 42 } 
val y = { println("y is evaluated"); 42 }
x

Will print:

y is evaluated
x is evaluated

because y is evaluated immediately, whereas x is evaluated only when we call it.

The other difference is whether the result of the computation is cached or not:

  • The value of val is evaluated once, and then cached
  • The value of def is evaluated every time we call the function

This is why

def dice = { new scala.util.Random().nextInt(6) + 1 }
val once = { new scala.util.Random().nextInt(6) + 1 }

println(dice + " <-> " + once)
println(dice + " <-> " + once)
println(dice + " <-> " + once)
println(dice + " <-> " + once)

will output:

5 <-> 6
4 <-> 6
6 <-> 6
5 <-> 6

that is, dice is a more or less useful random number generator that generates values 1-6, whereas once is a rather useless random value that is fixed once it's created.


Now, you can think of a 2x2-table with eager-vs-lazy in one dimension, and cached-vs-not-cached on the other:

  • val is eager and cached
  • lazy val is lazy and cached (so are memoized defs)
  • def is lazy and uncached
  • There is not really eager and uncached, because computing something and then immediately throwing it away is not very useful. Maybe there is one exception that gets pretty close: the entry point of the program, because even though def main is a def, it always gets called anyway, so in a sense it's both kind-of eager and uncached.

In your code, loop is essentially a tail-recursive version of the non-terminating

def loop: Boolean = { while (true) {}; true }

but since loop is a def, and therefore lazy, the right hand side is not evaluated when you define it.

If you now define

def x = loop

nothing is happening still, because x is also lazy, so the right hand side is again not evaluated.

But if you define

val x = loop

then x is a val, thus its right hand side is evaluated eagerly. On the right hand side of the definition, there is an invocation of loop. Now loop is accessed, and since it is a def, it now evaluates its body, and goes into an infinite loop.

like image 42
Andrey Tyukin Avatar answered Oct 01 '22 06:10

Andrey Tyukin