Search code examples
scalapass-by-name

Scala : Why should i save a by-name parameter as a Function0


I am working through a coursera example of Signal and cannot make sense of this syntax,

class Signal[T](expr: => T) {
 import Signal._
 private var myExpr: () => T = _
 private var myValue: T = _
 private var observers: Set[Signal[_]] = Set()
 private var observed: List[Signal[_]] = Nil
 update(expr)

The update method is written as

    protected def update(expr: => T): Unit = {
    myExpr = () => expr
    computeValue()
  }

I can understand that expr is being passed by name so is evaluated only when called. But what i cannot get my head around is why is the myExpr represented as () => T ? Also why is the assignment written as myExpr = () => expr . From what i understand () => expr denotes a Function0 that returns expr. I think my understanding of byname is wrong. Can someone please elaborate on this ?

Or can we rewrite the above syntax as follows,

  class Signal[T](expr: () => T) {
  import Signal._
  private var myExpr: () => T = _
  private var myValue: T = _
  private var observers: Set[Signal[_]] = Set()
  private var observed: List[Signal[_]] = Nil
  update(expr)

And the update method as ,

 protected def update(expr: () => T): Unit = {
    myExpr = expr
    computeValue()
  }

Solution

  • expr: => T
    

    as function argument stands for call-by-name that is not only delayed evaluation (aka lazy) but also that it is evaluated each time it is accessed.

    private var myExpr: () => T = _
    

    Indicates that it is a variable of type () => T which means that it takes no arguments and returns T. If you put expr: () => T as function argument it makes an argument of type () => T which, again, means it takes no arguments and returns T, which is NOT a call-by-name. These two things are slightly confusing because of syntax similarities but are quite different.

    You could use it like this:

    myExpr = () => 4
    myExpr() //evaluates as 4
    

    Whereas calling myExpr() without assigning () => 4 to it would throw java.lang.NullPointerException.

    In the coursera course Odersky explaines very well what is a call-by-name evaluation with his def loop: Unit = loop example.