1

I have a controller like this

def index = Action.async { implicit request =>
implicit val lang = Lang(Language.mapping.lift(request.queryString("country").head).getOrElse("en"))
  ///...
  futureResult.map{...}
  .recover {
      case error =>
        displayError(error)
    }
}

private def displayError(throwable: Throwable)(implicit lang: Lang) = {
    throwable match {     
      case error: NotFoundException => Status(404)(views.html.errors.notFound("resource.notfound"))
   //...
  }
}

And an error template :

@(message: String)(implicit lang: Lang)
<!DOCTYPE html>
<p>@Html(Messages(message))</p>
...

I've noticed a few things :

  • If val lang = ... is not defined as implicit, compile is still working, I can call displayError method
  • If you don't pass lang explicitly to the displayError like this : displayError(error)(lang), the value passed to the private method is not the one defined by my code, but the last one used by my browser (I guess in a cookie?)

So looking at the code it seems to be a simple private method call, but is Play doing some implicit values modifications before each method call, even private ones, even without passing through the router ?

Thanks

Nader Ghanbari
  • 4,120
  • 1
  • 23
  • 26
Loic
  • 3,310
  • 4
  • 25
  • 43

1 Answers1

2

From Play 2.3.x documents (refer to this page for more info):

Note: If you have an implicit Request in the scope, it will provide an implicit Lang value corresponding to the preferred language extracted from the Accept-Language header and matching one of the application supported languages. You should add a Lang implicit parameter to your template like this: @()(implicit lang: Lang).

So this happens because you have an implicit request in your scope. Yes, even for private methods, provided that your private method accepts lang as an implicit parameter, because implicit parameters will be transitively available.

If you don't want this behavior either remove the implicit from request parameter or provide your own language explicitly which is perfectly fine.

Nader Ghanbari
  • 4,120
  • 1
  • 23
  • 26
  • Thanks a lot, I was not thinking of the implicit request parameter. – Loic Nov 05 '14 at 16:35
  • Something I still find strange is that my implicit lang is defined after the implicit request. If I println my lang at the end of `index` the value is good, but at the beginning of `displayError` it's wrong – Loic Nov 05 '14 at 16:37
  • No worries. This is actually an implicit conversion from `Request` to `Lang`. It is the trickiest kind of implicit conversion because the subject to conversion is `implicit` itself! So it's an implicit conversion of an implicit parameter :) – Nader Ghanbari Nov 05 '14 at 16:43
  • What do you mean by wrong? Is it different or non-existing or ..? If you want to provide your own lang better to pass it explicitly to your methods for debugging purpose. Then you will find a good place to put it and use it in all controllers later. – Nader Ghanbari Nov 05 '14 at 16:52
  • 1
    By wrong I mean, the lang of the browser, not the lang I've defined in my implicit val lang. I just don't get why my implicit value does not override the implicit provided with the request (by implicit conversion) when I call my private method. Is there a way to force the overriding, other than explicit passing? – Loic Nov 05 '14 at 17:39
  • Of course you can remove `implicit` keyword from request. Then the only implicit `Lang` in your context will be the one you provide. For a better understanding of where Scala looks for implicits refer to [this SO thread](http://stackoverflow.com/questions/5598085/where-does-scala-look-for-implicits). – Nader Ghanbari Nov 06 '14 at 04:32