Reputation: 5137
I don't know how to articulate my question other than by providing an example of what I would like to do and explain why it doesn't work.
I would like to do something like the following:
def yes() { println("yes") }
def no() { println("no") }
def blank() {}
var handler: Option[() => Unit] = Some(blank)
...
handler = Some(yes)
...
handler.foreach(f => f())
This does not work because the defined functions are of type Unit, not () => Unit. So Some(blank) can not be assigned as type Option[()=>Unit].
Next I tried:
var handler: Option[Unit] = Some(blank)
...
handler = Some(yes)
...
handler.foreach(f => f())
This allows me to assign the functions to the handler, but then I can't invoke the function within Option's foreach function.
How can this be accomplished?
Upvotes: 1
Views: 103
Reputation: 38045
This does not work because the defined functions are of type Unit, not () => Unit. So Some(blank) can not be assigned as type Option[()=>Unit].
Actually it works as expected.
Type of expression yes()
is Unit
, but the type of expression yes
depends on context.
In context of () => Unit
compiler could convert yes
to something like () => yes()
.
You could create function () => Unit
from method yes
manually like this:
val functionYes = yes _
handler = Some(functionYes)
But compiler is smart enough to convert method to function in context where function is expected, like Some(yes)
.
Take a look at this example:
1 to 10 foreach println
println
here is the method Predef.println
, so compiler have to convert it to function.
Upvotes: 5
Reputation: 39577
It's worth supplying some vocabulary here.
The type of a method
def foo(): Unit = ???
is ()Unit
(3.3.1 method types in the spec).
If you leave off the parens,
def foo: Unit = ???
then the type is => Unit
.
That chapter of the spec calls them "non-value types" because you can't use them as a value.
If you want a value of type () => Unit
, it applies a conversion. See 6.26.5 of the spec, where it is called "eta expansion."
I bet you saw the failure by leaving off the parens at some point:
scala> def foo: Unit = ???
foo: Unit
scala> var handler: Option[() => Unit] = Some(foo)
<console>:8: error: type mismatch;
found : Unit
required: () => Unit
var handler: Option[() => Unit] = Some(foo)
^
In this case, the conversion you're getting is "evaluation" (6.26.2).
This is a case where it matters if you supplied parens in the method definition.
Since "procedure syntax" is deprecated, maybe it's useful to practice not using it.
Upvotes: 2