I was making my way through the Scala playframework tutorial and I came across this snippet of code which had me puzzled:
def newTask = Action { implicit request =>
taskForm.bindFromRequest.fold(
errors => BadRequest(views.html.index(Task.all(), errors)),
label => {
Task.create(label)
Redirect(routes.Application.tasks())
}
)
}
So I decided to investigate and came across this post.
I still don't get it.
What is the difference between this:
implicit def double2Int(d : Double) : Int = d.toInt
and
def double2IntNonImplicit(d : Double) : Int = d.toInt
other than the obvious fact they have different method names.
When should I use implicit
and why?
I'll explain the main use cases of implicits below, but for more detail see the relevant chapter of Programming in Scala.
Implicit parameters
The final parameter list on a method can be marked implicit
, which means the values will be taken from the context in which they are called. If there is no implicit value of the right type in scope, it will not compile. Since the implicit value must resolve to a single value and to avoid clashes, it's a good idea to make the type specific to its purpose, e.g. don't require your methods to find an implicit Int
!
example:
// probably in a library
class Prefixer(val prefix: String)
def addPrefix(s: String)(implicit p: Prefixer) = p.prefix + s
// then probably in your application
implicit val myImplicitPrefixer = new Prefixer("***")
addPrefix("abc") // returns "***abc"
Implicit conversions
When the compiler finds an expression of the wrong type for the context, it will look for an implicit Function
value of a type that will allow it to typecheck. So if an A
is required and it finds a B
, it will look for an implicit value of type B => A
in scope (it also checks some other places like in the B
and A
companion objects, if they exist). Since def
s can be "eta-expanded" into Function
objects, an implicit def xyz(arg: B): A
will do as well.
So the difference between your methods is that the one marked implicit
will be inserted for you by the compiler when a Double
is found but an Int
is required.
implicit def doubleToInt(d: Double) = d.toInt
val x: Int = 42.0
will work the same as
def doubleToInt(d: Double) = d.toInt
val x: Int = doubleToInt(42.0)
In the second we've inserted the conversion manually; in the first the compiler did the same automatically. The conversion is required because of the type annotation on the left hand side.
Regarding your first snippet from Play:
Actions are explained on this page from the Play documentation (see also API docs). You are using
apply(block: (Request[AnyContent]) ⇒ Result): Action[AnyContent]
on the Action
object (which is the companion to the trait of the same name).
So we need to supply a Function as the argument, which can be written as a literal in the form
request => ...
In a function literal, the part before the =>
is a value declaration, and can be marked implicit
if you want, just like in any other val
declaration. Here, request
doesn't have to be marked implicit
for this to type check, but by doing so it will be available as an implicit value for any methods that might need it within the function (and of course, it can be used explicitly as well). In this particular case, this has been done because the bindFromRequest
method on the Form class requires an implicit Request
argument.