`def` vs` val` vs` lazy val` in Scala

I understand correctly that

  • def is evaluated every time you access it

  • lazy val is evaluated after his access

  • val evaluated after it gets into the execution area?

+48
properties scala lazy-evaluation
Feb 26 2018-12-12T00:
source share
8 answers

Yes, although for the third I would say "when this statement is executed", because, for example:

 def foo() { new { val a: Any = sys.error("b is " + b) val b: Any = sys.error("a is " + a) } } 

This gives "b is null" . b never evaluated, and its error never occurs. But it is in scope as soon as the control enters the block.

+41
Feb 26 2018-12-12T00:
source share

Yes, but there is one good trick: if you have a lazy value, and during the first assessment he will get an exception, the next time you try to access it, he will try to overestimate himself.

Here is an example:

 scala> import io.Source import io.Source scala> class Test { | lazy val foo = Source.fromFile("./bar.txt").getLines | } defined class Test scala> val baz = new Test baz: Test = Test@ea5d87 //right now there is no bar.txt scala> baz.foo java.io.FileNotFoundException: ./bar.txt (No such file or directory) at java.io.FileInputStream.open(Native Method) at java.io.FileInputStream.<init>(FileInputStream.java:137) ... // now I've created empty file named bar.txt // class instance is the same scala> baz.foo res2: Iterator[String] = empty iterator 
+80
Feb 26 '12 at 3:00
source share

I would like to explain the differences in the example that I performed in REPL. I find this simple example easier to understand and explain the conceptual differences.

Here I create val result1, the lazy result of val2 and def def3, each of which is of type String.

BUT). Val

 scala> val result1 = {println("hello val"); "returns val"} hello val result1: String = returns val 

Here println is executed because the value of result1 is calculated here. So, now result1 will always refer to its value ie "returns val".

 scala> result1 res0: String = returns val 

So now you can see that result1 now refers to its value. Note that the println statement is not executed here because the value for result1 was already calculated when it was executed for the first time. So now, result1 will always return the same value, and the println statement will never be executed again, because the calculation to get the value of result1 has already been completed.

AT). lazy val

 scala> lazy val result2 = {println("hello lazy val"); "returns lazy val"} result2: String = <lazy> 

As we see here, the println instruction is not executed here, and not a single value has been computed. This is the nature of laziness.

Now, when I refer to result2 for the first time, the println statement will be executed, and the value will be calculated and assigned.

 scala> result2 hello lazy val res1: String = returns lazy val 

Now, when I turn to result2 again, this time we will only see its value, and the println instruction will not be executed. From now on, result2 will just behave like val and constantly return a cache value.

 scala> result2 res2: String = returns lazy val 

FROM). Protection

In the case of def, the result must be computed each time result3 is called. This is also the main reason that we define methods as def in scala, because methods must evaluate and return a value each time it is called inside the program.

 scala> def result3 = {println("hello def"); "returns def"} result3: String scala> result3 hello def res3: String = returns def scala> result3 hello def res4: String = returns def 
+11
Jan 03 '15 at 10:19
source share

One good reason to choose def over val , especially in abstract classes (or in traits that are used to simulate Java interfaces), is that you can override def with val in subclasses, but not vice versa.

As for lazy , there are two things that I can see that I need to keep in mind. Firstly, lazy enters some overhead at runtime, but I suppose you will need to check your specific situation to see if it really has a significant impact on runtime performance. Another problem with lazy is that it can delay the creation of an exception, which can complicate the discussion about your program, since the exception is not created in advance, but only at the first use.

+9
Nov 08
source share

You're right. To confirm the specification :

From "3.3.1 Method Types" (for def ):

Parametric methods are called expressions that are revised each time referring to the parameter name without parameters.

From "4.1 Declaration and Definition of Meanings":

Definition of the value val x : T = e defines x as the name of the value, which is obtained from the estimate e .

Defining a lazy value evaluates its right side e first time access is accessed.

+6
Feb 26 2018-12-12T00:
source share

def defines the method. When you call the method, the ofcourse method is executed.

val defines the value (immutable variable). An assignment expression is evaluated when the value is initialized.

lazy val defines a value with initialization delay. It will be initialized on first use, so the destination expression will be evaluated then.

+3
Feb 26 2018-12-12T00:
source share

The name assigned to def is evaluated by replacing the name and its RHS expression each time the name appears in the program. Therefore, this replacement will be performed every time a name appears in your program.

The name assigned to val is evaluated immediately when the control reaches its RHS expression. Therefore, every time a name appears in an expression, it will be considered as the value of this rating.

The name assigned by lazy val follows the same policy as the qualification val, except that its RHS will only be evaluated when the control hits the point where the name is used for the first time

+2
Oct 28 '14 at 17:20
source share

You should indicate a potential error when using the val value when working with values ​​unknown before runtime.

Take request: HttpServletRequest for example

If you would say:

 val foo = request accepts "foo" 

You will get a null pointer exception, as at the time of val initialization, the request does not have foo (it will be known only at runtime).

Thus, depending on the access / calculation flow, def or lazy val are suitable choices for values ​​determined at runtime; it or val, which itself is an anonymous function that retrieves runtime data (although the latter seems a bit more multiple)

+1
Apr 10 2018-12-12T00:
source share



All Articles