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))
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'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).
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.
The compiler is getting confused by an overloaded method definiton and I cannot find a way to clarify my intention sufficiently.
I have the following code:
val part: (QueryParams) => List[ResultMap] = (partOf.find _).andThen(makeMap)
The find method is overloaded:
def find(params: QueryParams): List[U] = ...
def find(params: QueryParams, flattener: U => T): List[T] = ...
The code was working fine as long as there was a single definiton of find. Since I had to add the second find definiton with 2 params, the compiler is generating this error:
Error:(15, 31) ambiguous reference to overloaded definition,
both method find in trait DataFetcher of type (params: ...QueryParams)List[...Parser]
and method find in trait DataFetcher of type (params: ...QueryParams, flattener: ...Parser => ...ResultTuple)List[...ResultTuple]
match expected type ?
val part: Fetcher = (partOf.find _).andThen(makeMap)
^
IMHO there is no ambiguity. The type of part is defined to accept one argument of type QueryParams. There is only one method accepting a single QueryParams. U and T are different types and makeMap expects a List[U] There are no implicits, default values or varargs involved.
Is there a way to further clarify my intention to the compiler?
EDIT: one way to remove the ambiguity is to introduce an intermediary value, clarifying the expected type of the eta expansion:
val find: (QueryParams) => List[ResultTuple] = partOf.find _
val part: (QueryParams) => List[ResultMap] = find andThen makeMap
But since makeMap is only accepting List[ResultTuple] I stil dont get the reason for the supposed ambiguity and would prefer not to introduce the extra value. Any clarification?
First, it is important to understand that the trailing underscore is a deliberate design decision to prevent programmer mistakes. The only exception is when the type is explicitly declared.
Here is an example illustrating this point.
object A {
def add(a: Int)(b:Int): Int = a + b
val x: Int => Int = add(5) // compiles fine
val y = add(5) // produces a compiler error
}
The same applies to your question. Because you do not specify the intermediate type, when you write find _, should the compiler infer the type to be QueryParams => List[ResultTuple] (as you may expect) or should it be (QueryParams, U => T) => List[ResultTuple]? Note that the trailing underscore does not stand for a single argument, it just lifts the method to a function. When the type if declared, you can drop the trailing underscore and write find where you would have written find _.
I see from your edit that you found out that an intermediate value with a declared type works. Another (slightly clunky) way to clarify your intent is the following.
val part: (QueryParams) => List[ResultMap] = (x => partOf.find(x)).andThen(makeMap)
Let's imagine the following items in scope:
object Thing {
var data: Box[String] = Empty
}
def perform[T](setter: Box[T] => Unit) {
// doesn't matter
}
The following fails to compile:
perform(Thing.data = _)
The error message is:
<console>:12: error: missing parameter type for expanded function ((x$1) => Thing.data = x$1)
perform(Thing.data = _)
^
<console>:12: warning: a type was inferred to be `Any`; this may indicate a programming error.
perform(Thing.data = _)
^
While the following compiles:
perform(Thing.data_=)
I have since surpassed this issue by creating a better abstraction, but my curiosity still remains.
Can anyone explain why this is?
Let's expand out what you're doing in the first example:
Thing.data = _
is shorthand for defining an anonymous function, which looks like:
def anon[T](x: Box[T]) {
Thing.data = x
}
So when you call
perform(Thing.data = _)
it's the same as
perform(anon)
The problem is anon and perform take a type parameter T and at no point are you declaring what T is. The compiler can only infer type parameters in a function call from passed arguments, not from within the function body, so it cannot infer in anon that T should be String.
Notice that if you call
perform[String](Thing.data = _)
the compiler has no issue because it now knows what T should be, and if you try to use any type besides string, you'll get a type mismatch error, but the error occurs in the body of the anonymous function, not on the call to perform.
However, when you call
perform(Thing.data_=)
you are passing the method Thing.data_=, which is explicitly defined as Box[String] => Unit, so the compiler can infer perform's type parameter because it is coming from a function argument.