(3) var, val and lazy
About
:octocat: GitHub: All of the example code: repo (link)
:page_facing_up: blog link: https://purrgramming.life/cs/programming/fp/ :star:
var vs val
In Java, you declare new variables like this:
String s = "hello";
int i = 42;
Person p = new Person("Victoria Pinzhen Liao");
Each variable declaration is preceded by its type.
Scala has two types of variables:
- valcreates an immutable variable (like- finalin Java, or- constantsin other languages)
- varcreates a mutable variable
This is what variable declaration looks like in Scala:
//  variable’s type is  _inferred_  by the compiler 
val s = "hello"   // immutable
var i = 42        // mutable
class Person(name: String)
val p = new Person("Victoria Pinzhen Liao")Those examples show that the Scala compiler is usually smart enough to infer the variable’s data type from the code on the right side of the  =  sign. We say that the variable’s type is  inferred  by the compiler. 
You can also explicitly declare the variable type if you prefer:
//  _explicitly_  declare the variable type 
val s: String = "hello"
var i: Int = 42Performance
val and var are evaluated when defined.
val  vs var
val  makes a variable  immutable  — like  final  in Java, i.e.  values
var  makes a variable  mutable.  i.e.  variables
val a = 'a'
a = 'b'Result
<console>:12: error: reassignment to valThat fails with a reassignment to val error, as expected. Conversely, you can reassign a  var:
var c = 'c'  
c = 'd' // This is fineResult
c: Char = dWhich One?
The general rule is that you should always use a  val  field unless there is a good reason not to. 
- makes your code more like algebra
- helps get you started down the path to functional programming, where all fields are immutable.
val  in REPL
The REPL is not 100% the same as working with source code in an IDE, so you can do a few things in the REPL that you cannot do when working on real-world code in a project. 
You can redefine a  val  field in the REPL, like this:
// It's ok only in REPL
scala> val age = 18
age: Int = 18
scala> val age = 19
age: Int = 19
val  fields cannot be redefined like that in the real world, but they can be redefined in the REPL playground.
val vs def
We use the keyword’ def to introduce a definition evaluated only when used.`
def introduces a definition where the right-hand side is evaluated on each use.
While the def  is a function declaration, it is evaluated on call, i.e. val  evaluates when defined,  def  – when called:
Example:
// Complain immediately
scala> val even: Int => Boolean = ???
scala.NotImplementedError: an implementation is missing
// Complain on call
scala> def even: Int => Boolean = ???
even: Int => Boolean
scala> even
scala.NotImplementedError: an implementation is missing
Function Identity
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 evenVal: Int => Boolean = _ % 2 == 0  
evenVal eq evenVal  
//Boolean = true  
Function Results
With  def  you can get new function on every call:
val randomInt: () => Int = {  
  val r = util.Random.nextInt  
  () => r  
}  
randomInt() // val res3: Int = 1764655189  
randomInt() // val res4: Int = 1764655189
// --------------------------------  
def randomIntDef: () => Int = {  
  val r = util.Random.nextInt  
  () => r  
}  
// Different  
randomIntDef()  
randomIntDef()
lazy val
lazy val is evaluated 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:
Identity
lazy val even: Int => Boolean = _ % 2 == 0  
even eq even  
//Boolean = trueResults
lazy val randomInt: () => Int = {  
  val r = util.Random.nextInt  
  () => r  
}  
randomInt()  
// Int = -1068569869  
randomInt()  
// Int = -1068569869 - same resultPerformance
val is evaluated when defined.
def is evaluated on every call so that performance could be worse than  val  for multiple calls. You will get the same performance with a single call. Furthermore, with no calls, you will get no overhead from  def, so you can define it even if you do not use it in some branches.
You will get a lazy evaluation with a  lazy val: you can define it even if you do not use it in some branches. It evaluates once or never, but you will get a little overhead from double-checking locking on every access to your  lazy val.
However, if you need a function (not a method) for function composition or higher-order functions (like  filter(even)) compiler will generate a function from your method every time you are using it as a function so that performance could be slightly worse than with  val.
 
        
This is true
Hi Bob : )
If you can reproduce this in the workspace with
def even: Int => Boolean = _ % 2 == 0even eq even
// Workspace result:
// def even: Int => Boolean
// val res1: Boolean = false