Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pros and Cons of choosing def over val

I'm asking a slight different question than this one. Suppose I have a code snippet:

def foo(i : Int) : List[String] = {
  val s = i.toString + "!" //using val
  s :: Nil
}

This is functionally equivalent to the following:

def foo(i : Int) : List[String] = {
  def s = i.toString + "!" //using def
  s :: Nil
}

Why would I choose one over the other? Obviously I would assume the second has a slight disadvantages in:

  • creating more bytecode (the inner def is lifted to a method in the class)
  • a runtime performance overhead of invoking a method over accessing a value
  • non-strict evaluation means I could easily access s twice (i.e. unnecesasarily redo a calculation)

The only advantage I can think of is:

  • non-strict evaluation of s means it is only called if it is used (but then I could just use a lazy val)

What are peoples' thoughts here? Is there a significant dis-benefit to me making all inner vals defs?

like image 402
oxbow_lakes Avatar asked Nov 09 '10 12:11

oxbow_lakes


People also ask

What does val Mean in code?

Val means its final, cannot be reassigned. Whereas, Var can be reassigned later.

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 -----


3 Answers

1)

One answer I didn't see mentioned is that the stack frame for the method you're describing could actually be smaller. Each val you declare will occupy a slot on the JVM stack, however, the whenever you use a def obtained value it will get consumed in the first expression you use it in. Even if the def references something from the environment, the compiler will pass . The HotSpot should optimize both these things, or so some people claim. See:

http://www.ibm.com/developerworks/library/j-jtp12214/

Since the inner method gets compiled into a regular private method behind the scene and it is usually very small, the JIT compiler might choose to inline it and then optimize it. This could save time allocating smaller stack frames (?), or, by having fewer elements on the stack, make local variables access quicker.

But, take this with a (big) grain of salt - I haven't actually made extensive benchmarks to backup this claim.

2)

In addition, to expand on Kevin's valid reply, the stable val provides also means that you can use it with path dependent types - something you can't do with a def, since the compiler doesn't check its purity.

3)

For another reason you might want to use a def, see a related question asked not so long ago:

Functional processing of Scala streams without OutOfMemory errors

Essentially, using defs to produce Streams ensures that there do not exist additional references to these objects, which is important for the GC. Since Streams are lazy anyway, the overhead of creating them is probably negligible even if you have multiple defs.

like image 163
axel22 Avatar answered Oct 07 '22 08:10

axel22


The val is strict, it's given a value as soon as you define the thing.

Internally, the compiler will mark it as STABLE, equivalent to final in Java. This should allow the JVM to make all sorts of optimisations - I just don't know what they are :)

like image 43
Kevin Wright Avatar answered Oct 07 '22 09:10

Kevin Wright


I can see an advantage in the fact that you are less bound to a location when using a def than when using a val.

This is not a technical advantage but allows for better structuring in some cases.

So, stupid example (please edit this answer, if you’ve got a better one), this is not possible with val:

def foo(i : Int) : List[String] = {
  def ret = s :: Nil
  def s = i.toString + "!"
  ret
}

There may be cases where this is important or just convenient.

(So, basically, you can achieve the same with lazy val but, if only called at most once, it will probably be faster than a lazy val.)

like image 36
Debilski Avatar answered Oct 07 '22 09:10

Debilski