I'm writing a function that looks like this:
def func(str: String, logFunction: String => Unit) = {
logFunction(s"message is: $str")
}
When I try to pass Logger.info from Play framework, I get this error:
type mismatch;
[error] found : (message: => String, error: => Throwable)Unit <and> (message: => String)Unit
[error] required: String => Unit
It seems like it found the function with two parameters, and tried to pass that to my function. How do I specify the one-parameter Logger.info to be passed to my function?
As you mentioned, there are two overloaded Logger.info methods in Play. To turn that method into a function and to choose the overload you want, you can explicitly specify the type and add an underscore after the function. The underscore turns a method into a function, which is sometimes done automatically, but in the case can be done explicitly. See also how to get a function from an overloaded method.
In this specific case try
val logger: String => Unit = Logger.info _
Related
My requirement is to return a function from another function in scala which takes variable argument i.e while executing the returned function , i can pass multiple argument at runtime.
My code looks like :
object VarArgTest {
def getFunction(): (Map[String, String],Map[String, Any]*) => Any={
(arg:Map[String,String], arg2:Map[String,Any]*) => "random"//this gives compilation error
}
}
In code , i want to return a function which take , Map[String,String] as one argument ,while the other Map[String,Any] should be optional to it.
But i get compilation error in return statement as follow:
type mismatch; found : (Map[String,String], Map[String,Any]) required: (Map[String,String], Map[String,Any]*) ⇒ Any
Can anyone help , what have i missed here?
Note: My requirement is that returned function can take either one argument (Map[String,String]) or it can take two arguments max (Map[String,String], Map[String,Any])
Thanks
It's impossible to use varargs in anonymous function.
You can get your piece of code working by making the returned function nested instead of anonymous like this:
object VarArgTest {
def getFunction(): (Map[String, String],Map[String, Any]*) => Any = {
def nestedFunction(arg:Map[String,String], arg2:Map[String,Any]*) = "random"
nestedFunction
}
}
However since you don't need multiple instances of Map[String, Any] but either none or one, you would be better off using Option[Map[String, Any]], providing None when it is not needed.
I was looking at the FoldLeft and FoldRight methods and the operator version of the method was extremely peculiar which was something like this (0 /: List.range(1,10))(+).
For right associative functions with two parameter lists one would expect the syntax to be something like this((param1)(param2) op HostClass).
But here in this case it is of the syntax (param1 op HostClass)(param2). This causes ambiguity with another case where a right associative function returns another function that takes a single parameter.
Because of this ambiguity the class compiles but fails when the function call is made as shown below.
class Test() {
val func1:(String => String) = { (in) => in * 2 }
def `test:`(x:String) = { println(x); func1 }
def `test:`(x:String)(y:String) = { x+" "+y }
}
val test = new Test
(("Foo") `test:` test)("hello")
<console>:10: error: ambiguous reference to overloaded definition,
both method test: in class Test of type (x: String)(y: String)String
and method test: in class Test of type (x: String)String => String
match argument types (String)
(("Foo") `test:` test)("hello")
so my questions are
Is this an expected behaviour or is it a bug?
Why the two parameter list right associative function call has been designed the way it is, instead of what I think to be more intuitive syntax of ((param1)(param2) op HostClass)?
Is there a workaround to call either of the overloaded test: function without ambiguity.
The Scala's Type System considers only the first parameter list of the function for type inference. Hence to uniquely identify one of the overloaded method in a class or object the first parameter list of the method has to be distinct for each of the overloaded definition. This can be demonstrated by the following example.
object Test {
def test(x:String)(y:Int) = { x+" "+y.toString() }
def test(x:String)(y:String) = { x+" "+y }
}
Test.test("Hello")(1)
<console>:9: error: ambiguous reference to overloaded definition,
both method test in object Test of type (x: String)(y: String)String
and method test in object Test of type (x: String)(y: Int)String
match argument types (String)
Test.test("Hello")(1)
Does it really fail at runtime? When I tested it, the class compiles, but the call of the method test: does not.
I think that the problem is not with the operator syntax, but with the fact that you have two overloaded functions, one with just one and the other with two parameter lists.
You will get the same error with the dot-notation:
test.`test:`("Foo")("hello")
If you rename the one-param list function, the ambiguity will be gone and
(("Foo") `test:` test)("hello")
will compile.
Here is my code
class AuthAction(callbackUri:String) extends ActionBuilder[UserRequest] with ActionRefiner[Request,UserRequest]{
override def refine[A](request: Request[A]): Future[Either[Result,UserRequest[A]]] = {
val redirectUri = routes.Application.callback(None, None).absoluteURL(request)
getUser(request) match {
case Some(user) => Future.successful(Right(new UserRequest(user,request)))
case _ => Future.successful(Left(oauthLogin(callbackUri,redirectUri)(request)))
}
}
}
When i try to compile this code, i get the following error
[error] (secure: Boolean)(implicit request: play.api.mvc.RequestHeader)String <and>
[error] (x$1: play.mvc.Http.Request)String
[error] cannot be applied to (play.api.mvc.Request[A])
[error] val redirectUri = routes.Application.callback(None, None).absoluteURL(request)
is this something to do with implicit params? whats happening here?
It wants play.mvc.Http.Request, and you are trying to pass in play.api.mvc.Request. They are not compatible.
Edit: To answer the question you are asking in the comment ...
Well, I am not sure which parameter you are talking about. There are two flavors of this function:
The one, that it seems like you are trying to call -
absoluteURL(request: play.mvc.Http.Request) - does not take any implicit params, it just needs the request of the right type.
The other one - absoluteURL(secure: Boolean)(implicit request: play.api.mvc.RequestHeader) - does have an implicit parameter, which is also of a different type from what you have (RequestHeader, not Request).
If you declare a variable holding this requestHeader as implicit, and it is in scope, you can call the latter function without specifying it explicitly:
implicit val requestHeader = createMyRequestHeader()
routes.Application.callback(None, None).absoluteURL(true)
or you can still pass it in explicitly like you would do with a regular parameter (in this case you don't need it to be declared as implicit):
routes.Application.callback(None, None).absoluteURL(true)(requestHeader)
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))
Hello there Stack Overflow,
I hope you'll help me with my very first question here :)
So I'm having a problem with Scala type inference. Here is the code:
object Problem {
def ok(fn: (String) => Unit) = fn("")
// type mismatch; found: java.lang.String("") required: String
def fail[String](fn: (String) => Unit) = fn("")
}
What kind of String does Scala expect here?
Note that this is a minimal example to explain my problem. The original issue appeared when I tried to implement a more complex interface (Play's Iteratee, to be precise), so, no, leaving out the [String] is not an option. (If anyone thinks that the actual code would help, I'll provide it.)
I tried def fail[java.lang.String] ... but then it says expected ], found ..
I did read Scala String vs java.lang.String - type inference which gives a good explanation on java.lang.String vs. scala.Predef.String, but I still could not come up with a solution for my specific problem.
Any ideas?
EDIT: So here is the original attempt how I tried to implement http://www.playframework.org/documentation/api/2.0/scala/play/api/libs/iteratee/Iteratee.html only that I wrote String instead of T. (With T it compiles, and it makes sense!) My fail; obviously I was a bit overwhelmed by all the type parameters:
val stream = WS.url("url").get({ headers =>
(new Iteratee[Array[Byte], String] {
def fold[T](done: (String, Input[Array[Byte]]) => Promise[T],
cont: (Input[Array[Byte]] => Iteratee[Array[Byte], String]) => Promise[T],
error: (String, Input[Array[Byte]]) => Promise[T]): Promise[T] =
{
done("something", Input.Empty)
}
})
})
Regards,
Hendrik
When you write:
def fail[String](fn: (String) => Unit) = fn("")
The type parameter between square brackets String is just an arbitrary name that, in your case, will hide scala or java string. It is fully equivalent to:
def fail[T](fn: (T) => Unit) = fn("")
If you want to constrain the type to string, you just have to write:
def fail(fn: (String) => Unit) = fn("")
And it will work for scala and java strings (since they are the same).
This problem has nothing to do with Java vs Scala strings.
In the line def fail[String](fn: (String) => Unit) = fn("") you're definining a completely new type parameter and naming it String. This shadows the general definition.
A type paramter is needed if you intend to abstract over the type. You are not doing this in the fail example, and this should be dropped.
If you are overriding something that uses a type parameter, then you should specify this at the class level:
class A extends B[String]
Looking at the code for Iteratee, I'll guess you're trying to implement fold with its various done, cont and error functions. Fold only has one type paramter, which is used in the return type, so I'm not sure where this can come from. The input type parameters are specified on the class, so if you extend Iteratee[String, Unit] these should be provided.