Reputation: 697
My Scala level is a beginner and I saw an action method clearly demonstrating a declaration implicit request=>
. And my question is under what types of situation should we declare clearly? I also have seen methods which don't declare implicit request=>
or request=>
.
Could anyone explain the advantage?
Upvotes: 2
Views: 3638
Reputation: 136
Another example with similar API to play's implicit req => ...
case class ClassName(name: String)
def log(msg: String)(implicit className: ClassName) =
System.out.println(s"message=`$msg` className=`${className.name}`")
val cls = Option(ClassName("ImplicitClass"))
cls.foreach { implicit name =>
log("explicit message")
}
Produces
message=`explicit message` className=`ImplicitClass`
Upvotes: 1
Reputation: 1072
I will not cover the meaning of implicit
in scala itself as it has already been answered on stackoverflow here. The play documentation also explains the use of request =>
here but does not give examples of a useful implicit request.
TL; DR : when in doubt, use implicit request
as it may be needed by some components.
If the request
does not change the result your block of code will return, it can be omitted and you can write.
def myAction = Action { Ok("Hello World") }
If on the other hand you need to use the content of the request (header or body), then you have to add a request
parameter. A common example of this is parsing the body of the request :
Action(parse.json) { request => // it works without implicit
request.body.validate[MyClass].fold(/* do something */)
}
The play documentation encourages us to mark the request parameter as implicit
because even if you do not use the request directly, one component you use may need it as an implicit. If you ever get a missing implicit error in one of your action, it probably boils down to the fact that you forgot to make your request implicit.
I think a good example you might encounter in play is the internationalization API. To sum up, it allows to automatically inject localized messages in your templates depending on the Accept-Language
header in the request. All you have to do is add the I18nSupport
trait to your controller and inject a messagesApi: MessagesApi
parameter (and obviously define your internationalized messages). Then, in your twirl template, you can use the localized messages. For instance :
Template :
@()(implicit messages: Messages)
@*
message will be in english, spanish, klingon... depending on the supported
languages and request Accept-Language header
*@
@messages("say-hello")
Controller :
class MyController @Inject() (val messageApi: MessageApi) extends Controller with I18nSupport {
def myAction = Action {implicit request =>
// We do not have to bother about how messages are injected
// The I18nSupport trait does the work for us
Ok(html.myTemplate())
}
}
To be able to do this, the I18nSupport
trait contains a def :
implicit def request2Messages(implicit request: RequestHeader): Messages = /* ... */
It allows to get an instance of Messages
automatically (the compiler will implicitly call request2Messages(yourRequest)
when needed but you need to have an implicit request (or request header) in scope.
Another example I have seen is automatically getting a user instance in the scope of the action when using some security frameworks in play.
A annoying gotcha with this kind of implicit chain is that if you forget to make your request implicit, the compiler will probably complain about a missing implicit Messages
in scope while the real problem is a missing implicit request.
Upvotes: 8
Reputation: 4794
implicit
in Scala has many use cases - one of them being passing parameters implicitly to functions that define implicit parameters.
For example:
def withImplicitParameter(greeting: String)(implicit name: String): Unit = {
println(greeting + " " + name)
}
// Using implicits
implicit val name = "Bob"
withImplicitParameter("Hello") // "Bob" is passed in implicitly for name parameter. Prints "Hello Bob"
withImplicitParameter("Bye")("Joe") // "Joe" is passed in explicitly for name parameter. Prints "Bye Joe"
Therefore unless one of the functions you're calling has an implicit parameter of the type Request
you don't need { implicit request => ... }
More info can be found in Scala's official documentation on implicit parameters
Upvotes: 2