Can someone explain to me what's the use of implicit keyword in the following Play Action:
def index = Action { implicit request =>
Async {
val cursor = collection.find(
BSONDocument(), BSONDocument()).cursor[Patient]
val futureList = cursor.toList
futureList.map { patients => Ok(Json.toJson(patients)) }
}
}
Thanks in advance.
In all Scala (not just Play), an argument to an anonymous function can be marked implicit just as with methods. Within the body of the function, the implicit parameter is visible and can be resolved to an appropriate value in scope.
In this case, request is the argument of the anonymous function that describes what the action will do. The implicit lets the function be called with any value of type Request that happens to be in scope so you don't have to provide the Request instance yourself. You can trust it will be there so you can focus on the work of handling the request.
Related
I have one controller action implemented like this:
def doChangePassword = deadbolt.Restrict(List(Array(Application.USER_ROLE_KEY)))()
{ request => // <<<<<<<<<<<< here is the request
Future {
val context = JavaHelpers.createJavaContext(request)
com.feth.play.module.pa.controllers.AuthenticateBase.noCache(context.response())
val filledForm = Account.PasswordChangeForm.bindFromRequest
// compilation error here, it can't see the request ^^^^^^^
if (filledForm.hasErrors) {
// User did not select whether to link or not link
BadRequest(views.html.account.password_change(userService, filledForm))
} else {
val Some(user: UserRow) = userService.getUser(context.session)
val newPassword = filledForm.get.password
userService.changePassword(user, new MyUsernamePasswordAuthUser(newPassword), true)
Redirect(routes.Application.profile).flashing(
Application.FLASH_MESSAGE_KEY -> messagesApi.preferred(request)("playauthenticate.change_password.success")
)
}
}
}
the implementation above leads to the compilation error:
[error] /home/bravegag/code/play-authenticate-usage-scala/app/controllers/Account.scala:74: Cannot find any HTTP Request here
[error] val filledForm = Account.PasswordChangeForm.bindFromRequest
[error] ^
[error] one error found
However, if I change line 2 from:
{ request => // <<<<<<<<<<<< here is the request
to
{ implicit request => // <<<<<<<<<<<< here is the request
then it compiles ... but why?
What you are looking for are Implicit Parameters. In short:
Implicit Parameters can be passed just like regular or explicit parameters. In case you do not provide an implicit parameter explicitly, then the compiler will try to pass one for you. Implicits can come from various places. From the FAQ Where does Scala look for implicits?:
First look in current scope
Implicits defined in current scope
Explicit imports
wildcard imports
Now look at associated types in
Companion objects of a type
Implicit scope of an argument’s type (2.9.1)
Implicit scope of type arguments (2.8.0)
Outer objects for nested types
Other dimensions
Implicits under number 1. take precedence over those under number 2.
By marking request as implicit in your example, you are declaring an "Implicit defined in current scope". You need to have an implicit request in place because bindFormRequest "asks" you to pass one. See its signature:
bindFromRequest()(implicit request: Request[_]): Form[T]
Now that you have an implicit request in scope, the compiler will automatically pass it to bindFormRequerst.
As I mentioned in the beginning, you could also pass request explicitly:
val filledForm = Account.PasswordChangeForm.bindFromRequest()(request)
In the latter case there is no need to declare request as implicit as you are obviously passing request explicitly. Both variants are equal. It's up to you which one you prefer.
you need an implicit request in scope, like this: https://github.com/pedrorijo91/play-slick3-steps/blob/master/app/controllers/ApplicationController.scala#L11
Why does the following Play syntax work
def handleForm = Action(parse.tolerantFormUrlEncoded) { implicit request =>
val username = request.body.get("username").map(_.head).getOrElse("");
Ok("Username was " + username)
}
Without specifying the type of request, how would the compiler know how to resolve the implicit?
An Action in Play can be seen as a function: Request[A] => Result. Internally an Action is defined like trait Action[A] extends EssentialAction
The type A is actually the one which allows you to put anything in there. As you can see from the code, the Request is defined like this: trait Request[+A] extends RequestHeader. Interesting here is also the plus sign (+). It is the so-called covariant annotation. This covariant type parameter is one which is allowed to vary down as the class is subtyped. It means that if you have something like
trait List[+A]
then List[Int] is a subtype of List[AnyVal] because Int is a subtype of AnyVal. This means that you may provide an instance of List[Int] when a value of type List[AnyVal] is expected.
All this allows you to have a super generic request which serves as a base for your action and therefore no compile time troubles should be expected.
And something as for why is this all necessary from a more user-related point of view:
From the Play Scala documentation:
It is often useful to mark the request parameter as implicit so it can
be implicitly used by other APIs that need it:
Action { implicit request =>
Ok("Got request [" + request + "]")
}
It doesn't actually resolve the implicit, you mark the parameter as implicit, for further method calls inside the request handler. Whenever you call a method which accepts an implicit Request parameter, the request argument from the request handler will be automatically passed to it. If you wouldn't mark the request argument as implicit, you'd have to explicitly pass the request argument for each method call who needs an implicit request parameter.
update: upon your comment I updated your code with type parameters to clarify. So even when you use different BodyParsers, your request parameter is still going to be of Request type, so there is no need to convert it, it's just going to be parametrized differently based on your body parser. request.body is going to have the same type as the type parameter, Map[String, Seq[String]] in this example. If you use a JSON body parser then your request parameter would be a Request[JsValue], and the request.body is a JsValue.
def handleForm: Action[Map[String, Seq[String]]] = Action(parse.tolerantFormUrlEncoded)({
implicit request: Request[Map[String, Seq[String]]] =>
val username = request.body.get("username").map(_.head).getOrElse("")
Ok("Username was " + username)
})
tl;dr You can just do Action(...) { request => ... } if you don't need an implicit Request for further method calls inside the request handler
I try to feel the advantage of implicit parameters in Scala. (EDITED: special case when anonymous function is used. Please look at the links in this question)
I try to make simple emulation based on this post. Where explained how Action works in PlayFramework. This also related to that.
The following code is for that purpose:
object ImplicitArguments extends App {
implicit val intValue = 1 // this is exiting value to be passed implicitly to everyone who might use it
def fun(block: Int=>String): String = { // we do not use _implicit_ here !
block(2) // ?? how to avoid passing '2' but make use of that would be passed implicitly ?
}
// here we use _implicit_ keyword to make it know that the value should be passed !
val result = fun{ implicit intValue => { // this is my 'block'
intValue.toString // (which is anonymous function)
}
}
println(result) // prints 2
}
I want to get "1" printed.
How to avoid passing magic "2" but use "1" that was defined implicitly?
Also see the case where we do not use implicit in definition, but it is there, because of anonymous function passing with implicit.
EDITED:
Just in case, I'm posting another example - simple emulation of how Play' Action works:
object ImplicitArguments extends App {
case class Request(msg:String)
implicit val request = Request("my request")
case class Result(msg:String)
case class Action(result:Result)
object Action {
def apply(block:Request => Result):Action = {
val result = block(...) // what should be here ??
new Action(result)
}
}
val action = Action { implicit request =>
Result("Got request [" + request + "]")
}
println(action)
}
Implicits don't work like this. There is no magic. They are just (usually) hidden parameters and are therefore resolved when invoking the function.
There are two ways to make your code work.
you can fix the implicit value for all invocations of fun
def fun(block: Int=>String): String = {
block(implicitly[Int])
}
implicitly is a function defined in Predef. Again no magic. Here's it's definition
def implicitly[A](implicit value: A) = value
But this means it will resolve the implicit value when declaring the fun and not for each invocation.
If you want to use different values for different invocations you will need to add the implicit paramter
def fun(block: Int=>String)(implicit value: Int): String = {
block(value)
}
This will now depend on the implicit scope at the call site. And you can easily override it like this
val result = fun{ _.toString }(3)
and result will be "3" because of the explicit 3 at the end. There is, however, no way to magically change the fun from your declaration to fetch values from implicit scope.
I hope you understand implicits better now, they can be a bit tricky to wrap your head around at first.
It seems that for that particular case I asked, the answer might be like this:
That this is not really a good idea to use implicit intValue or implicit request along with implicitly() using only one parameter for the function that accept (anonymous) function.
Why not, because:
Say, if in block(...) in apply() I would use implicitly[Request], then
it does not matter whether I use "implicit request" or not - it will use
request that is defined implicitly somewhere. Even if I would pass my
own request to Action { myOwnRequest =Result }.
For that particular case is better to use currying and two arguments and.. in the second argument - (first)(second) to use implicit
Like this:
def apply(block:Request => Result)(implicit request:Request):Action2
See my little effort around this example/use case here.
But, I don't see any good example so far in regards to how to use implicit by passing the (anonymous) function as argument (my initial question):
fun{ implicit intValue => {intValue.toString}
or that one (updated version):
val action = Action { implicit request =>
Result("Got request [" + request + "]")
}
I understand implicit parameters and implicit conversions in Scala but I saw this for the first time today: the implicit keyword in front of a parameter in an anonymous function:
Action { implicit request =>
Ok("Got request [" + request + "]")
}
What does the implicit keyword do here?
Are there resources on the web that describes more on what the use case is?
There are two distinct features here.
First, request isn't really an argument in a method invocation. It's the argument of an anonymous function. The anonymous function itself is the argument of the method invocation.
Second, declaring an implicit argument in an anonymous function have the convenience of saving you from "forcing" a val into a implicit:
Action { request =>
implicit val r = request
Ok("Got request [" + request + "]")
}
I happen to know this a Play framework code, but I am not sure what are the signatures for Action and Ok. I will guess that they are something like that:
def Action(r:Request => Result):Unit
case class Ok(str:msg)(implicit r:Request)
Again, it's pure guessing for illustrative purposes only.
Found a few resources:
https://issues.scala-lang.org/browse/SI-1492
https://stackoverflow.com/a/5015161/480674
search for "Implicit arguments in closures" on the second link
In my understanding, the keyword of Implicit means Let complier do the job
Declaring an implicit variable means it can be used for implicit parameter of other methods inside the scope. In other words, the variable is being considered by the compiler to fill in implicit parameters.
def index = Action { implicit request =>
val str = sayHi("Jason")
Ok(views.html.index("Your new application is ready." + str))
}
private def sayHi(name: String)(implicit req: Request[AnyContent]) = name + ", you can the following content" + req.body
I declare an implicit parameter req in sayHi with type Request[AnyContent], however, I can call the method with only first parameter sayHi("Jason") because the implicit parameter req is filled in by the compiler to reference the implicit variable request
I understand implicit parameters and implicit conversions in Scala but I saw this for the first time today: the implicit keyword in front of a parameter in an anonymous function:
Action { implicit request =>
Ok("Got request [" + request + "]")
}
What does the implicit keyword do here?
Are there resources on the web that describes more on what the use case is?
There are two distinct features here.
First, request isn't really an argument in a method invocation. It's the argument of an anonymous function. The anonymous function itself is the argument of the method invocation.
Second, declaring an implicit argument in an anonymous function have the convenience of saving you from "forcing" a val into a implicit:
Action { request =>
implicit val r = request
Ok("Got request [" + request + "]")
}
I happen to know this a Play framework code, but I am not sure what are the signatures for Action and Ok. I will guess that they are something like that:
def Action(r:Request => Result):Unit
case class Ok(str:msg)(implicit r:Request)
Again, it's pure guessing for illustrative purposes only.
Found a few resources:
https://issues.scala-lang.org/browse/SI-1492
https://stackoverflow.com/a/5015161/480674
search for "Implicit arguments in closures" on the second link
In my understanding, the keyword of Implicit means Let complier do the job
Declaring an implicit variable means it can be used for implicit parameter of other methods inside the scope. In other words, the variable is being considered by the compiler to fill in implicit parameters.
def index = Action { implicit request =>
val str = sayHi("Jason")
Ok(views.html.index("Your new application is ready." + str))
}
private def sayHi(name: String)(implicit req: Request[AnyContent]) = name + ", you can the following content" + req.body
I declare an implicit parameter req in sayHi with type Request[AnyContent], however, I can call the method with only first parameter sayHi("Jason") because the implicit parameter req is filled in by the compiler to reference the implicit variable request