I\'m trying to represent a function that takes no arguments and returns no value (I\'m simulating the setTimeout function in JavaScript, if you must know.)
c
case class Scheduled(time : Int, callback : => Unit)
The case
modifier makes implicit val
out of each argument to the constructor. Hence (as someone noted) if you remove case
you can use a call-by-name parameter. The compiler could probably allow it anyway, but it might surprise people if it created val callback
instead of morphing into lazy val callback
.
When you change to callback: () => Unit
now your case just takes a function rather than a call-by-name parameter. Obviously the function can be stored in val callback
so there's no problem.
The easiest way to get what you want (Scheduled(40, println("x") )
where a call-by-name parameter is used to pass a lambda) is probably to skip the case
and explicitly create the apply
that you couldn't get in the first place:
class Scheduled(val time: Int, val callback: () => Unit) {
def doit = callback()
}
object Scheduled {
def apply(time: Int, callback: => Unit) =
new Scheduled(time, { () => callback })
}
In use:
scala> Scheduled(1234, println("x"))
res0: Scheduled = Scheduled@5eb10190
scala> Scheduled(1234, println("x")).doit
x
In the question, you want to simulate SetTimeOut function in JavaScript. Based on previous answers, I write following code:
class Scheduled(time: Int, cb: => Unit) {
private def runCb = cb
}
object Scheduled {
def apply(time: Int, cb: => Unit) = {
val instance = new Scheduled(time, cb)
Thread.sleep(time*1000)
instance.runCb
}
}
In REPL, we can get something like this:
scala> Scheduled(10, println("a")); Scheduled(1, println("b"))
a
b
Our simulation doesn't behave exactly the same as SetTimeOut, because our simulation is blocking function, but SetTimeOut is non-blocking.
The => Type
notation stands for call-by-name, which is one of the many ways parameters can be passed. If you aren't familiar with them, I recommend taking some time to read that wikipedia article, even though nowadays it is mostly call-by-value and call-by-reference.
What it means is that what is passed is substituted for the value name inside the function. For example, take this function:
def f(x: => Int) = x * x
If I call it like this
var y = 0
f { y += 1; y }
Then the code will execute like this
{ y += 1; y } * { y += 1; y }
Though that raises the point of what happens if there's a identifier name clash. In traditional call-by-name, a mechanism called capture-avoiding substitution takes place to avoid name clashes. In Scala, however, this is implemented in another way with the same result -- identifier names inside the parameter can't refer to or shadow identifiers in the called function.
There are some other points related to call-by-name that I'll speak of after explaining the other two.
The syntax () => Type
stands for the type of a Function0
. That is, a function which takes no parameters and returns something. This is equivalent to, say, calling the method size()
-- it takes no parameters and returns a number.
It is interesting, however, that this syntax is very similar to the syntax for a anonymous function literal, which is the cause for some confusion. For example,
() => println("I'm an anonymous function")
is an anonymous function literal of arity 0, whose type is
() => Unit
So we could write:
val f: () => Unit = () => println("I'm an anonymous function")
It is important not to confuse the type with the value, however.
This is actually just a Function1
, whose first parameter is of type Unit
. Other ways to write it would be (Unit) => Type
or Function1[Unit, Type]
. The thing is... this is unlikely to ever be what one wants. The Unit
type's main purpose is indicating a value one is not interested in, so doesn't make sense to receive that value.
Consider, for instance,
def f(x: Unit) = ...
What could one possibly do with x
? It can only have a single value, so one need not receive it. One possible use would be chaining functions returning Unit
:
val f = (x: Unit) => println("I'm f")
val g = (x: Unit) => println("I'm g")
val h = f andThen g
Because andThen
is only defined on Function1
, and the functions we are chaining are returning Unit
, we had to define them as being of type Function1[Unit, Unit]
to be able to chain them.
The first source of confusion is thinking the similarity between type and literal that exists for 0-arity functions also exists for call-by-name. In other words, thinking that, because
() => { println("Hi!") }
is a literal for () => Unit
, then
{ println("Hi!") }
would be a literal for => Unit
. It is not. That is a block of code, not a literal.
Another source of confusion is that Unit
type's value is written ()
, which looks like a 0-arity parameter list (but it is not).
I do it this way (just don't want to break apply):
case class Thing[A](..., lazy: () => A) {}
object Thing {
def of[A](..., a: => A): Thing[A] = Thing(..., () => a)
}
and call it
Thing.of(..., your_value)