This question already has an answer here:
Implicit parameter for literal function
(1 answer)
Closed 6 years ago.
Most of the play framework I see the block of code
// Returns a tasks or an 'ItemNotFound' error
def info(id: Long) = SecuredApiAction { implicit request =>
maybeItem(Task.findById(id))
}
yes my understanding is define a method info(id: Long) and in scala doc to create function in scala the syntax look like this:
def functionName ([list of parameters]) : [return type] = {
function body
return [expr]
}
Can you tell me what is the meaning of implicit request => and SecuredApiAction put before {
play.api.mvc.Action has helper methods for processing requests and returning results. One if it's apply overloads accepts a play.api.mvc.Request parameter:
def apply(request: Request[A]): Future[Result]
By marking the request parameter as implicit, you're allowing other methods which implicitly require the parameter to use it. It also stated in the Play Framework documentation:
It is often useful to mark the request parameter as implicit so it can
be implicitly used by other APIs that need it.
It would be same if you created a method yourself and marked one if it's parameters implicit:
object X {
def m(): Unit = {
implicit val myInt = 42
y()
}
def y()(implicit i: Int): Unit = {
println(i)
}
}
Because there is an implicit in scope, when invoking y() the myInt variable will be implicitly passed to the method.
scala> :pa
// Entering paste mode (ctrl-D to finish)
object X {
def m(): Unit = {
implicit val myInt = 42
y()
}
def y()(implicit i: Int): Unit = {
println(i)
}
}
// Exiting paste mode, now interpreting.
defined object X
scala> X.m()
42
Related
There is a note in Cay Horstmann's book "Scala for the Impatient" about the apply method:
Occasionally, the () notation conflicts with another Scala feature:
implicit parameters. For example, the expression "Bonjour".sorted(3)
yields an error because the sorted method can optionally be called
with an ordering, but 3 is not a valid ordering.
The solution is to assign "Bonjour".sorted to a variable and call apply on it, for example:
val result = "Bonjour".sorted
result(3)
Or call apply explicitly:
"Bonjour".sorted.apply(3)
But why this doesn't work and produces a compile error:
("Bonjour".sorted)(3)
The sorted method returns a String, which can be imlicitly converted to a StringOps and parentheses are used to wrap the string expression.
Why compiler doesn't accept to call the apply method of a StringOps?
You can use -Xprint:parser to see that the parens are discarded early:
scala> implicit class x(val s: String) { def scaled(implicit i: Int) = s * i }
defined class x
scala> "hi".scaled(5)
res0: String = hihihihihi
scala> { implicit val n: Int = 5 ; "hi".scaled }
res1: String = hihihihihi
scala> "hi".scaled(5)(3)
res2: Char = i
scala> { implicit val n: Int = 5 ; ("hi".scaled)(3) }
res3: String = hihihi
scala> :se -Xprint:parser
scala> { implicit val n: Int = 5 ; ("hi".scaled)(3) }
[[syntax trees at end of parser]] // <console>
package $line8 {
object $read extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
import $line3.$read.$iw.$iw.x;
object $iw extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
val res4 = {
implicit val n: Int = 5;
"hi".scaled(3)
}
}
}
}
}
res4: String = hihihi
scala>
The extra parens do nothing. The compiler just sees an application expr(args). Because it's an application, you don't get "implicit application" conversion.
In any case, the meaning of scaled, a method, depends on the expected type.
The reason we expect the extra parens to make a difference is that parens override precedence of operators. But (x) is just x.
Possibly the spec is actually clear about this:
e(args) requires that e be applicable to the args. In particular, the args are typechecked according to the parameter types of e.
e(args) is taken as e.apply(args) if e is a value, but scaled is a method.
You're hoping for "implicit application" to insert the implicit args, but that only applies when e is not already applied. Or that (e)(args) could be taken as (e(_))(args), that is, (x => e(x))(arg).
When written as e.apply(arg), the e is not an application like e(arg), so you benefit from conversions like implicit application.
Consider following code snippet:
object Example {
def run(f: => Unit): Unit = {
implicit val i = 1
f
}
def caller(): Unit =
run {
todo
}
def todo(implicit i: Int): Unit =
println(i)
}
which currently is not compiling with following message:
Error:(14, 13) could not find implicit value for parameter i: Int
todo
^
My question is it possible to make implicit parameter available to call-by-name function body?
EDIT
I tried make it working with macro implementation as suggested by Alexey Romanov
import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
object Macros {
def run(f: => Unit): Unit = macro runImpl
def runImpl(c : Context)(f: c.Tree) = {
import c.universe._
q"""{
implicit val i: Int = 3
$f
}"""
}
}
object Example extends App {
Macros.run {
todo
}
def todo(implicit i: Int): Unit =
println(i)
}
Debugging macro i can see that it is correctly expanded into
{
implicit val i: Int = 3
Example.this.todo
}
Unfortunately it does not compiles as well with same error that implicit is not found.
Digging into issue i found discussions here and jira issues https://issues.scala-lang.org/browse/SI-5774
So question is the same: Is it possible to tunnel implicit into todo function in this case?
Simply said - no. implicit requires that it is obvious from the code what is going on. If you want anything to be passed to a function implicitly, it must have implicit parameter which is not the case of your f function.
This is a great source of wisdom related to implicit:
http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html
My question was more about why implicit defined in run is not tunneled into caller's run body
Because that's simply not how lexical scoping works. It isn't in scope where the body is defined. You have two good alternatives:
def run(f: Int => Unit) = f(1)
run { implicit i =>
todo // can use i here
}
Make run a macro. This should be at least an approximation (adapted from SI-5778), unfortunately I can't test it at the moment:
object Macros {
def run(f: => Unit) = macro runImpl
def runImpl(c : Context)(f: c.Tree) = q"""{
implicit val i: Int = 1
// some other implicits
$f
}"""
}
1) How is this construction called? Cannot google it.
2) Why it doesn't work? I expect message be printed.
class A {
def m() {
println("m()")
}
}
object Main {
def main(args: Array[String]) {
val fun = (_: A).m _
fun(new A())
}
}
As om-nom-nom says, the conversion of methods to functions is called "partial application." It can be expressed explicitly by using underscore(s) as "arguments" to a method or automatically by the compiler when the available type information is sufficient for it to infer that a method name used in a place where a function is required can be partially applied to produce the required function.
Now, for your code. As written, the result of the call fun(new A()) is a Function1[Unit, Unit]. You'd have to apply that function to get the println invoked
// Exiting paste mode, now interpreting.
defined class A
defined module Main
scala> Main.main(Array())
scala> def doIt { val fun = (_: A).m _; fun(new A())() }
doIt: Unit
scala> doIt
m()
Is there a way to pass an implicit parameter into a curried function. I am using a dirty fix (se below) but it is not pretty. I would love to be able to pass the implicit var "i" as a implicit param.
case class myLoaner() {
implicit val i = "How to get this val into scope within the session function"
def withCode[T](session: => T): Either[Exception, T] = {
try {
Right(session)
} catch {
case ex: Exception => {
Left(ex)
}
}
}
}
object Test {
def main(args: Array[String]) {
val r = myLoaner()
r.withCode {
implicit val imp = r.i // I want to get rid of this line of code and use the implict val defined above directly
val h = new Helper
h.run
}
}
class Helper {
def run(implicit i: String) {
println(i)
}
}
}
After val r = myLoaner(), you can write
import r.i
or
import r._
to do what you want. Alternatively, you can mark r itself implicit and provide this extra definition:
implicit def loanerString(implicit loaner: myLoaner): String = loaner.i
... but now a little bit too many implicits start floating around for my taste, so use that wisely. Sometimes too much implicit magic harms the readability and understandability of your code.
You can always pass implicit parameters directly, e.g. as h.run(r.i).
I'm implementing a Java interface with a lot of methods with Object parameters, which in my case are really Strings containing user names:
public interface TwoFactorAuthProvider {
boolean requiresTwoFactorAuth(Object principal);
... //many more methods with the same kind of parameter
}
I'm trying to use implicit conversion to convert these to User objects in my implementation:
class TwoFactorAuthProviderImpl(userRepository: UserRepository)
extends TwoFactorAuthProvider {
def requiresTwoFactorAuth(user: User): Boolean = {
...
}
}
When I define the conversion in the companion object of my class, it is picked up just fine and my class compiles:
object TwoFactorAuthProviderImpl {
implicit def toUser(principal: Any): User = {
null //TODO: do something useful
}
}
However, to be able to do the conversion, I need access to the user repository, which the TwoFactorAuthProviderImpl instance has, but the companion object does not. I thought I could possibly use an implicit parameter to pass it:
implicit def toUser(principal: Any)(implicit repo: UserRepository): User = {
val email = principal.asInstanceOf[String]
repo.findByEmail(email)
}
But with the implicit parameter, the conversion is no longer picked up by the compiler (complaining that I'm not implementing the interface).
Is there a way to get the implicit conversion that I want, or is this outside the scope of what you can do with implicits?
This should work just fine - can you supply the exact compilation error? Not implementing what interface? It looks like you would have to declare as follows:
class TwoFactorAuthProviderImpl(implicit userRepository: UserRepository)
Here's an example for the REPL to show that implicits can have implicits; I'm using paste mode to ensure that module X is the companion object of the class X
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class X(i: Int, s: String)
object X { implicit def Int_Is_X(i: Int)(implicit s: String) = X(i, s) }
// Exiting paste mode, now interpreting.
defined class X
defined module X
scala> val i: X = 4
<console>:9: error: value X is not a member of object $iw
val i: X = 4
^
But if we add an implicit string in scope
scala> implicit val s = "Foo"
s: java.lang.String = Foo
scala> val i: X = 4
i: X = X(4,Foo)
Implicits advice
Don't go overboard with implicit conversions - I think you are going too far in this sense - the principal is implicitly a mechanism by which you can discover a user, it is not implicitly a user itself. I'd be tempted to do something like this instead:
implicit def Principal_Is_UserDiscoverable(p: String) = new {
def findUser(implicit repo: UserRepository) = repo.findUser(p)
}
Then you can do "oxbow".findUser
Thanks to Oxbow's answer, I now have it working, this is only for reference.
First of all, a value that should be passed as an implicit must itself be marked implicit:
class TwoFactorAuthProviderImpl(implicit userRepository: UserRepository) ...
Second, implicit conversions are nice and all, but a method implementation signature must still match the signature of its declaration. So this does not compile, even though there is a conversion from Any to User:
def requiresTwoFactorAuth(principal: User): Boolean = { ... }
But leaving the parameter as Any, as in the declaration, and then using it as a user works just fine:
def requiresTwoFactorAuth(principal: Any): Boolean = {
principal.getSettings().getPhoneUsedForTwoFactorAuthentication() != null
}
Also, the conversion really doesn't have to be in the companion object in this case, so in the end, I left the implicit parameters out.
The full source code:
class TwoFactorAuthProviderImpl(userRepository: UserRepository)
extends TwoFactorAuthProvider {
private implicit def toUser(principal: Any): User = {
val email = principal.asInstanceOf[String]
userRepository.findByEmail(email)
}
def requiresTwoFactorAuth(principal: Any): Boolean = {
//using principal as a User
principal.getSettings().getPhoneUsedForTwoFactorAuthentication() != null
}
...
}