2

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?

Kazuya Tomita
  • 667
  • 14
  • 34

3 Answers3

8

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.

Action without request

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") }

With Request

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 */)
}

With implicit request

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.

Side note

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.

Community
  • 1
  • 1
archz
  • 1,073
  • 13
  • 19
  • Although this is a tiny question, is `Message` an instance? If so, `messages("say-hello")` is quite strange because it appears `"say-hello"` seems to be the argument. And in your example, the template has to receive `Message` instance, so I think you should write like this: `Ok(html.myTemplate(messages))` where `messages` is the instance of `Message`. Could you add more detailed explanation about it? I know these are basic things, sorry. – Kazuya Tomita Jan 23 '17 at 02:39
  • Scala allows you to write myInstance(myParam) as long as your object defines a `apply` method so `messages("say-hello")` is just a shorthand for `messages.apply("say-hello")`. The omission of the `messages` argument in Ok(html.myTemplate()) is intentional. This is the whole point of using an implicit parameter. The compiler guess the `messages` argument from the context. [Jacob's answer](http://stackoverflow.com/a/41790056/2935481) and [this question](http://stackoverflow.com/questions/10375633/understanding-implicit-in-scala?rq=1) might help you understand the concept of implicit in scala. – archz Jan 23 '17 at 17:36
2

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

Jacob Wang
  • 4,411
  • 5
  • 29
  • 43
  • 3
    Just as a side note, never use basic types as implicits. Wrap them in case classes. – Reactormonk Jan 22 '17 at 11:07
  • @Reactormonk So, isn't the answer appropriate because he uses the basic type as an implicit? – Kazuya Tomita Jan 23 '17 at 07:50
  • It's merely a simple example of how implicit parameters work in Scala. The main point of my answer is unless you are calling a function that requires an implicit `Request`, there's no need to mark your request object as implicit – Jacob Wang Jan 23 '17 at 11:03
1

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`
pvlbzn
  • 138
  • 7