I'm currently starting with play framework, but my Scala knowledge is not sufficient.
As I know the => indicates that IsAuthenticated has some kind of functions as parameter.
I found out as well the f: => String... is a function with no input value. But how do I interprete the complete line with its 3 => ?
And further down, what exactly happens in the second line with => f(user)(request)? What is the target function for user and request object?
def IsAuthenticated(f: => String => Request[AnyContent] => Result) = Security.Authenticated(username, onUnauthorized) { user =>
Action(request => f(user)(request))
}
=> String => Request[AnyContent] => Result
is easier to read with parens added:
=> (String => (Request[AnyContent] => Result))
You can try this in the REPL. For example:
scala> def foo(f: => String => Int => Char): Char = f("abcdefgh")(4)
foo: (f: => String => (Int => Char))Char
In this example, f is a nullary function call-by-name parameter that returns a function (let's call that function g). g is a function that accepts a String parameter and returns yet another function (h). h is a function that accepts an Int parameter and returns a Char.
Example invocation:
scala> foo { s: String => { i: Int => s.charAt(i) } }
res0: Char = e
Let's walk through the type of each expression in the method body as it's evaluated:
f
Type: String => (Int => Char)
Value: { s: String => { i: Int => s.charAt(i) } }
f("abcdefgh")
Type: Int => Char
Value: { i: Int => "abcdefgh".charAt(i) }
f("abcdefgh")(4)
Type: Char
Value: 'e'
A couple of additions to the accepted answer
About Security.Authenticated
Security.Authenticated(username, onUnauthorized) { user =>
Action(request => f(user)(request))
}
Security.Authenticated - seems to be a function that takes two lists of parameters. The first list of parameters:
(username:String, onUnauthorized:Boolean)
and the second list is one argument:
(g:User => Action)
The complete signature can be something like:
def Authenticated(username:String, onUnauthorized:Boolean)(g:User => Action)
Action seems to be a class that takes a function in it's constructor:
class Action(h:Request => Result)
The argument to the constructor is a new function
def hActual(request:Request):Result = f(user)(request)
(the def should have user in the scope, because it is not given in arguments. For instance, hActual can be declared immediately before Action constructor call:
def IsAuthenticated(f: => String => Request[AnyContent] => Result) = Security.Authenticated(username, onUnauthorized) { user =>
def hActual(request:Request):Result = f(user)(request)
Action(hActual)
}
)
Also It seems so that the constructor can be called using curring:
def IsAuthenticated(f: => String => Request[AnyContent] => Result) = Security.Authenticated(username, onUnauthorized) { user =>
Action(f(user))
}
Related
Going through a tutorial on Spray, I encountered this:
entity(as[Quiz]) { quiz => requestContext =>
val responder = createResponder(requestContext)
createQuiz(quiz) match {
case true => responder ! QuizCreated
case _ => responder ! QuizAlreadyExists
}
}
This specific line is where the confusion lies:
entity(as[Quiz]) { quiz => requestContext =>
What in the world is with the second => sign???
What does this syntax mean and where can I find the documentation for further reading??
If I put the parenthesis like this, does it make more sense?
entity(as[Quiz]) { quiz => (requestContext =>
...
)
}
}
This is just a curried function with two arguments, and mechanically it is a function that returns another function. Example:
val test: Int => Int => Int = a => b => a + b // the same as a => (b => a + b)
println(test(2)(3)) //5
You can think of it as (a, b) => a + b, but with the added benefit so you can partially apply it easier:
val t: Int => Int = test(2)
println(t(3)) // 5
In the file https://github.com/playframework/playframework/blob/master/framework/src/play/src/main/scala/play/api/mvc/Security.scala, it has the following example code in a comment:
//in a Security trait
def username(request: RequestHeader) = request.session.get("email")
def onUnauthorized(request: RequestHeader) = Results.Redirect(routes.Application.login)
def isAuthenticated(f: => String => Request[AnyContent] => Result) = {
Authenticated(username, onUnauthorized) { user =>
Action(request => f(user)(request))
}
}
//then in a controller
def index = isAuthenticated { username => implicit request =>
Ok("Hello " + username)
}
So I tried to write some similar code:
def test1(a: =>Int=>Int=>Int):String="1"
test1 {1 => 1 => 1} // But this line doesn't compile.
I called it the same way as isAuthenticated is called, so why doesn't my code compile?
test1 {1 => 1 => 1} doesn't compile because {1 => 1 => 1} isn't a valid function definition. {x => y => 1}, on other hand, does compile. This is because 1 cannot be used as the name for a parameter.
Take a look at what happens when you paste def test1(a: =>Int=>Int=>Int):String="1" into the Scala REPL:
test1: (a: => Int => (Int => Int))String
test becomes defined as a function that accepts an another function as it's parameter. Notice the extra parenthesis in the REPL output. a is a function that maps Int to another function Int => Int.
So something like this would be more appropriate:
def a(i: Int): Int => Int = {j: Int => i + j}
test1(a)
This is a function in the zentask example in Application.scala.
I'm trying to understand it...
What does the f: => String mean?
What about the chaining of f: => String => Request[AnyContent] => Result
/**
* Action for authenticated users.
*/
def IsAuthenticated(f: => String => Request[AnyContent] => Result) =
Security.Authenticated(username, onUnauthorized) { user =>
Action(request => f(user)(request))
}
A parameter of the form fn: => String represents a 'generator' (either a function or a value) that returns (or is) a String, so, for example, you might have a method defined as
def myMethod(fn: => String): String = "Fn output = " + fn
and call this as follows (the return types I use here can typically be inferred by the compiler, I'm just adding them for pedagogical purposes):
def myFn: String = "Hello!"
// Alternatively: def myFn(): String = "Hello!"
// or: val myFn: () => String = "Hello!"
// or most simply: val myString = "Hello!"
val output = myMethod(myFn) // output = "Fn output = Hello!"
Building on this, we can define a method that takes a function that turns a String into an Int, eg:
def my2ndMethod(fn: String => Int): Int = fn("4")
and call it as follows:
def my2ndFn(input: String) = 5 * input.toInt
// Alternatively: val my2ndFn: String => Int = input => 5 * input.toInt
val output2 = my2ndMethod(my2ndFn _) // output2 = 20
In the case you provide, you have a more complicated entity: something that returns (or is) a function that takes a String and returns a further function that in turn takes a Request[AnyContent] and (finally) returns a Result (phew!).
You can also think of this as taking a function defined and used as follows:
def authFn(username: String)(request: Request[AnyContent]): Result
val authenticatedResult = IsAuthenticated(authFn _)
Actually it is a bit tricky to figure out how the operator associates:
f: => String => Request[AnyContent] => Result
is the same as
f: (=> String) => (Request[AnyContent] => Result)
So f is a function that takes a => String and returns a function that takes a request and returns a result. As I indicated in my comment, have a look at Need plain english translation of the following scala snippet for an explanation of some of what's going on.
So why have => String as the first argument versus just String? My guess is that it comes into play if you intended the user to pass a function that has its first argument by name (meaning it is evaluated every time it is needed).
So say you have a method g:
def g(s: => String): String => String = arg => s + arg
If you want to write a method m that takes the method g as an argument, then you need to write it like this:
def m(f: (=> String) => (String => String)) = f("a")("b")
m(g) // compiles
If you write it like this:
def n(f: String => (String => String)) = f("a")("b")
n(g) // does not compile
// found : => String => (String => String)
// required: String => (String => String)
This is the action composition taken from a sample that comes with the Play Framework
def IsAuthenticated(f: => String => Request[AnyContent] => Result) = Security.Authenticated(username, onUnauthorized) { user =>
Action(request => f(user)(request))
}
So, Security.Authenticated takes an username: RequestHeader => Option[String] and onAuthorized: RequestHeader=>SimpleResultand the second group of parantheses take String => Action[A]
And then in the controller I have:
def index = isAuthenticated { ...code }}
The code above is this, so I assume this is the f function => String => Request[AnyContent] => Result. Now, what I don't understand is what really happens here. I am not talking about User.findByEmail...., I'm talking about username => _ => .... What would the signature of this function look like if I called it directly?
username => _ =>
User.findByEmail(username).map { user =>
Ok(
html.dashboard(
Project.findInvolving(username),
Task.findTodoInvolving(username),
user
)
)
}.getOrElse(Forbidden)
If there was def isAuthenticated(f: => Request[AnyContent] => Result) I'd know how to use it and I'd understand it. But the extra "data" is confusing me.
UPDATE:
I guess I found something:
def f2: String => Int => List[Char] = x => _ => x.toList
And this would be called as:
f2("Andrew")(2) //there can be anything replacing 2 because I don't have access to it anyway
So the function above that I asked primarily about would be:
def f: => String => Request[AnyContent] => Result = username => _ => User.find.....
Am I right?
I get a "No by name parameter allowed here error".
If they don't use the second parameter why are they using String => Request => Result and not just simply String => Result?
That function definition is actually a curried function definition.
String => Request => Result actually means: f(s:String):(r:Request)=>Result ie a function that takes a String and returns a function that takes a Request and returns a Result.
Check out the part "Spicing up your functions": http://danielwestheide.com/blog/2013/01/30/the-neophytes-guide-to-scala-part-11-currying-and-partially-applied-functions.html
For me, the examples at https://github.com/mariussoutier/PlayBasics/tree/master/play-2.2-migration are very enlightening.
In Scala I have the following trait:
trait Reactive {
type Condition = () => Boolean
type Reaction = (Condition) => Unit
var reactions = Map[Condition, Reaction]()
def addReaction(c: Condition, r: Reaction) { reactions += (c -> r) }
def addReactions(rs: List[Tuple2[Condition, Reaction]]) {
for(r <- rs) r match { case(condition, reaction) => addReaction(condition, reaction) }
}
def updateReactive() {
for(reaction <- reactions) reaction match {
case (c, r) => r(c)
}
}
}
then when I am trying to call the addReactions() method:
addReactions(List(
(() => UserInput.lastInput.isKeyHit('g'), () => (is: Boolean) => activateDevice(0))
))
I get the following error message on the second argument of the tuple:
type mismatch; found : () => Boolean => Unit required: () => Boolean => Unit
I do not understand why. What do I have to do in order for the Reactive trait to store a set of boolean-conditioned functions that should be executed later, if their condition function returns true. Maybe I am going a round way? Is there any simpler approach?
Try writing this instead:
addReactions(List(
(() => UserInput.lastInput.isKeyHit('g'), condition => activateDevice(0))
))
() => (is: Boolean) => activateDevice(0) is a function with no parameters that returns a function from Boolean to Unit. condition => activateDevice(0) is a function with a single parameter called condition (whose type, () => Boolean, is inferred) and returns Unit.