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:
def
is lifted to a method in the class)s
twice (i.e. unnecesasarily redo a calculation)The only advantage I can think of is:
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 val
s def
s?
Val means its final, cannot be reassigned. Whereas, Var can be reassigned later.
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 -----
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 def
s to produce Streams
ensures that there do not exist additional references to these objects, which is important for the GC. Since Stream
s are lazy anyway, the overhead of creating them is probably negligible even if you have multiple def
s.
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 :)
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
.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With