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()
}
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.