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!
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.
Here is a possible explanation!
scala> foo _
res14: () => Unit = <function0>
scala> foo
foo got called
scala>
Can you see why now?
Because Button takes a (delayed) Unit as a constructor argument, you'd think that the call to new Button(foo _) wouldn't be allowed because () => Unit is not the same thing as =>Unit. But it turns out that => Unit is, essentially, the universal accepter.
new Button()
new Button(99)
new Button("str")
You'll get warnings, but these all compile and run, and you can invoke the fire method on them (but it won't do anything).
Related
I have a generic function that looks like so
def getFromCacheOrCallService[T: ClassTag](cacheKey: String, duration: Duration = cacheDefaultDuration)(
callServiceToFetchValue: => Try[T]
): Try[T]
and Im trying to figure out how to mock this function in a way that will always call callServiceToFetchValue and use it instead. I have this so far
doAnswer(invocation => {
invocation.getArgumentAt(1, classOf[() => Try[marketplace]])()
}).when(marketplaceCache).cacheable(any(), any())(any())(any())
Which if I understand what Im doing correctly should call the function passed, but whenever I try to run I get this error
Invalid use of argument matchers!
4 matchers expected, 3 recorded:
Why is it saying it expects 4 matchers? I have 4 matchers, I dont understand what the problem is.
It's not the curried function that's the problem, it's the pass-by-name parameter.
Mockito doesn't support it very well, and I am not aware of any good workarounds aside from actually declaring that parameter as an actual function () => Try[T]
(or, perhaps, String => Try[T] - it actually looks a bit weird without the key being passed it).
For anyone who ran into a similiar problem the solution I ended up with was changing the defintion of getFromCacheOrCallService to
def getFromCacheOrCallService[T: ClassTag](cacheKey: String, duration: Duration = cacheDefaultDuration)(
callServiceToFetchValue:() => Try[T]
): Try[T]
And then it worked. However since most of the time I was passing in functions like
def getFromCacheOrCallService("key", Duration(10, MINUTES)(callServiceToFetchValue(SomeInput))
I had to change it to
def getFromCacheOrCallService("key", Duration(10, MINUTES)({ () => callServiceToFetchValue(SomeInput)} )
I have a method which returns Future[Unit], so when I call whenReady
These two options work: whenReady(doItAsync())(_ => {}) and whenReady(doItAsync()) { _ => }
but this doesn't: whenReady(doItAsync())(() => {})
Are not _ of type Unit and empty params list equivalent in this case?
Although type Unit is similar to void from other languages it is not exactly the same.
This particular trouble comes from a limitation in Java (and thus Scala) generics implementation: they are implemented using type erasure. Particularly it means that generic method can't change the number of arguments. Now what happens when type parameter is Unit? We still must have the same number of arguments and also can't magically change return type to return nothing (void) because this will be a different signature. So the answer is to use some fake type with only fakes values: scala.runtime.BoxedUnit. And thus Unit might represent actual parameter that you don't need but has to be there. And so type signature () => {} doesn't match that because it takes no parameters.
Note also that in Java itself there is the same issue and thus there is a similar thing called java.lang.Void
Update:
To make the point more clear consider following generic vs. non-generic code:
def foo(f: () => String) = println(f())
def fooGeneric[T](arg: T, f: (T) => String) = println(f(arg))
foo(() => "Non-generic")
fooGeneric[Unit]((), (_) => "generic")
Note that also logically fooGeneric[Unit] is the same as foo, you still have to pass first argument and pass function that accept an (useless) argument as the second parameter.
Are not _ of type Unit and empty params list equivalent in this case?
No. _ => {} defines a function with single parameter (which happens in this context to have type Unit), () => {} defines a function with no parameters. Their types are Unit => Unit and () => Unit, or without syntactic sugar Function1[Unit, Unit] and Function0[Unit]. These types aren't actually related: neither of them is a subtype of the other.
You can write a single-argument anonymous function taking Unit with () using pattern-matching: { case () => ... }. But there is no point to doing that.
I thought () was the only instance of Unit in Scala.
When I try to set a function to anonymous func variable, this works:
def some(a:Unit):Unit = {
println("Enigma")
}
val func:Unit => Unit = some
func()
But this does not:
def some():Unit = {
println("Enigma")
}
val func:Unit => Unit = some
An empty parameter list as in your second example is not the same as Unit which is a value that represents something like null. () doesn't always mean Unit in every context,
specifically the instance where your dealing with an argument list.
This is because your second example is a method without any arguments.
Take a look at the types that results:
some: (a: Unit)Unit
some: ()Unit
which would be written in a type assignment as
Unit => Unit
() => Unit
In the second case, the parens are not acting as Unit, but instead are merely the string representation of an argumentless function. () is only symbolic as Unit in the context of a method. In a type signature you use Unit, because () is expected to be a function with no arguments
def some(): Unit
The () here is not the instance of Unit, just no argument.
The normal usage of () is
def some(): Unit = ()
But if you enter Some() in Scala interpreter, you will get
scala> Some()
res0: Some[Unit] = Some(())
Well, it's strange, seems that Scala rewrites Some() to Some(()). Anyway, I will not write code like this, it makes things hard to understand.
What is type of this block: callback: => Unit?
How I can assign it to Option? In other words how to update following code so it doesn't have any compilation errors?
var onEventCallback: Option[() => Unit] = None
def onEvent(callback: => Unit) {
onEventCallback = Some(callback) // HERE compilation error: Some[Unit] doesn't conform to Option[() => Unit]
}
Ok. I solved it using Some(callback _) instead of Some(callback). But why this work?
The compiler needs to know whether you want callback to be executed immediately or not. WIthout the underscore immediate execution is assumed, and the result is assigned to the Some. WIth the underscore, the compiler knows that it shouldn't execute callback to get the result but should treat it as the parameter to pass to the Some constructor (or rather, apply() method).
But why this work?
Sometimes you can think of by-name parameter as a function without arguments. Actually it is a Function0 after erasure phase in compiler. You could compile you code with -Xprint:erasure to see this:
def onEvent(callback: Function0): Unit = onEventCallback_=(new Some(callback))
I am new to Scala. I have been searching but there is no easy "search string" for the seemingly easy question I have.
def foo( f: (String) => String ){println(f("123"))}
foo{_+"abc"} //works
def bar( f :() => String ){println(f())}
bar{"xyz"} // why does this not work?
def baz( f: => String ){println(f)}
baz{"xyz"} //works
Why does the second (bar) not work?
Second baz works because it's not a function literal, but a call-by-name parameter. Basically what it does is delaying the moment of argument computation until it's needed in the program. You can also read about this in this question.
As for bar you just need to pass a function like bar{() => "xyz"}
bar accepts a function that takes no arguments and returns String. You gave it just a String. To make it work:
bar{() => "xyz"}
This case is special to parameterless functions/blocks.
object Fs2 {
def f0=1
def f0_1()=1
}
object Main extends App {
println(Fs2.f0)
//println(Fs2.f0()) wont compile
println(Fs2.f0_1)
println(Fs2.f0_1())
}
Unit "()" is optional for f0_1. Adding it to f0 will cause an error. f0 does not accept any parameter. Unit itself is a parameter declaring there is no parameter. Fs2.f0 corresponds to baz, Fs2.f0() corresponds to bar.