axiopisty
axiopisty

Reputation: 5137

Create an Option of type function so the function can be executed later?

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

Answers (2)

senia
senia

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

som-snytt
som-snytt

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

Related Questions