Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scala: difference between function and function _

Tags:

scala

I'm getting some unexpected behavior when using a call by name function in Scala. Can anybody explain the difference here?

class Button( act: => Unit) {def fire = act}
def foo() {println("foo got called")}
val x= new Button(foo)
x.fire
val y= new Button(foo _)
y.fire

x.fire causes foo to be called. y.fire does not. Why? What function is being passed to y? Thanks!

like image 438
ConorR Avatar asked Sep 14 '25 09:09

ConorR


1 Answers

You should probably define your class a bit differently.

class Button( act: () => Unit) {def fire = act()}

Notice you are now taking in a Function0[Unit] instead of a call-by-name Unit value. This new definition has better typesaftey since it requires a function, while yours will accept any value, and will do nothing unless there are side effect required to evaluate the value passed in. We also now call the function passed in for its side effects instead of just returning it.

The problem with Unit is that when a unit is required any value can be provided which will be automatically discarded for a Unit. For example, with your code new Button(5) is valid, as is the code val x: Unit = 5.

The reason the first code class Button( act: => Unit) {def fire = act} "works", is you call the method foo, and pass the result into the Button constructor. Since it's a by-name parameter foo doesn't actually run until it's used. When you then use the Unit value passed into the class, the expression needs to be evaluated so foo is fun.

You second example is different however, adding the underscore (foo _) now means that you are passing in the method itself as a function, instead of calling the method and passing in the result as in your first example. It's perfectly fine to pass a function in to the constructor even thought the type now is not Unit since as discussed earlier any value can be discarded and replaced by Unit. When you evaluate the Unit value, there are no side effects this time since you don't run the method to get the unit, just create a function which is the discarded without being run. def fire = act

When you change the type to be a function.

class Button( act: () => Unit) {def fire = act()}

now only a () => Unit is a valid argument instead of anything, and the fire method runs that function.

like image 75
puhlen Avatar answered Sep 16 '25 04:09

puhlen