4

While reading Play! Framework documentation, I came across this snippet:

def index = Action { implicit request =>
  session.get("connected").map { user =>
    Ok("Hello " + user)
  }.getOrElse {
    Unauthorized("Oops, you are not connected")
  }
}

Documentation explains implicit there:

Alternatively you can retrieve the Session implicitly from a request

Besides, I read this post: Literal with Implicit and it seems logically that function cannot have implicit parameter.

If I well figured out, this is because a function, contrary to method has always a contract (interface).

Indeed, for instance, Function1[Int, Function1[Int, Int]] has as a return type's first parameter an Int, and thus prevents us to annotate this one as implicit. This would lead to a confusion about its high-level return type: () => Int or Int => Int ...

Therefore, what the previous snippet code behaves with implicit since first Action's required parameter is a literal function.

I guess the reason allowing compiler to accept this code is the multiple signatures of Action.apply() method:

  • def apply(block: Request[AnyContent] => Result): Action[AnyContent]
  • def apply(block: => Result): Action[AnyContent] (redirecting to the first one)

Since the second doesn't need some parameter, is this one selected in presence of a literal function's implicit parameter?

Community
  • 1
  • 1
Mik378
  • 21,881
  • 15
  • 82
  • 180

1 Answers1

6

Consider the following code:

class MyImplicitClass(val session: Int)
object Tester {
  def apply(fun: MyImplicitClass => Int): Int = ???
  def apply(fun: => Int): Int = ???
}
Tester { implicit myImplicitClass => session * 20}

If this function:

def session(implicit myImplicitClass: MyImplicitClass): Int = myImplicitClass.session

is in scope, then the first code snippet will compile, because clearly the implicit parameter myImplicitClass will be passed to the function session in order to access the field myImplicitClass.session, allowing you to omit the field access. This is exactly the trick the Play! Framework is using, check Controller to find the session function.

As a side note, the above closure is not stating that it takes an implicit parameter, it's a language feature to avoid having to do the following:

Tester { myImplicitClass => 
  implicit val x = myImplicitClass
  session * 20
}

when one wants to use a closure parameter as an implicit value in the body of the closure. Also note that as of Scala 2.9, you are limited to closures with exactly 1 parameter for this trick.

kiritsuku
  • 52,967
  • 18
  • 114
  • 136
Alex DiCarlo
  • 4,851
  • 18
  • 34
  • I don't have Play! setup on the computer with me at the moment, so unfortunately I can't look further into why this compiles with Play!, I setup a hierarchy the same as the Play! sources and could not figure out what they meant by "you can get session implicitly from request" and then simply drop the access from request and refer to session directly... This may just be an error in their documentation, but I'm not really sure. – Alex DiCarlo Jan 11 '13 at 01:52
  • I'm currently writing a possible answer (to my own question :)) – Mik378 Jan 11 '13 at 01:56
  • `implicit request =>` is the same as `implicit test =>` in my example. Additionally, calling it with your replacement wouldn't make sense, as it is a parameter to a function, not a value. I renamed it to `myImplicitClass` to make it more clear. – Alex DiCarlo Jan 11 '13 at 02:34
  • When you try to compile the code snippet in question from the Play! documentation, does it throw any errors? – Alex DiCarlo Jan 11 '13 at 02:44
  • Amazing, I'm very interested in the explanation, hopefully someone can illuminate this issue. – Alex DiCarlo Jan 11 '13 at 02:48
  • I've found ... The explanation is ridiculous: In controller's hierarchy, there's this declaration: `implicit def session(implicit request: RequestHeader) = request.session`. Why couldn't I find it early? because my snippet code test deals with implicit but request.session calls instead of session directly..... blend of the both snippets ;) – Mik378 Jan 11 '13 at 02:52
  • Oh I see, so the code snippet is being called within a class that inherits from `Controller`? – Alex DiCarlo Jan 11 '13 at 02:57
  • Controller.scala, and actually, the goal of making argument request of the function literal `implicit` allows `session` to be called without need to precise its `request` argument. Indeed, one rule is: one function's parameter implicit allows subsequent function's calls within this function to benefit of this implicity. – Mik378 Jan 11 '13 at 03:01
  • Right, thats the exact conclusion I came to in my above edit, well done! That's definitely an interesting piece of trivia. – Alex DiCarlo Jan 11 '13 at 03:06
  • With your third edit you just have understood what is going on. Now, delete all the other useless (and also wrong) stuff to provide a clean and correct answer. – kiritsuku Jan 11 '13 at 07:44
  • @sschaef Indeed, my previous "theory" was perfectly wrong ;), deleted :) – Mik378 Jan 11 '13 at 11:03