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)
Related
I have some code block like this:
object EntryPoint extends App {
val arr = ArrayBuffer(1, 2, 3)
doFirst(arr)
def doFirst(a: ArrayBuffer[Int]) = {
doSecond(s"$a")
}
def doSecond(
x: => String = ""
) = {
x match {
case s: String => println(s"This is string: $s")
case _ => println(x.getClass.getName)
}
}
}
Output: This is string: ArrayBuffer(1, 2, 3)
Why x evaluated like a string if in debugger i see lambda with 3 arguments?
Is it because every call x is x.apply() ?
A by-name parameter like x: => String is conceptually the same as a function with signature () => String
The following are equivalent and as you noticed already both parameters end up with the same runtime representation when debugging.
def doWithByNameParam(x: => String): String =
x
def doWithFunction(x: () => String): String =
x.apply()
doWithByNameParam("string")
doWithFunction(() => "string")
You just avoid some boilerplate with doWithByNameParam
Later Edit:
Here's what javap will give just so you understand what happens under the hood
public static java.lang.String doWithByNameParam(scala.Function0<java.lang.String>);
public static java.lang.String doWithFunction(scala.Function0<java.lang.String>);
while reviewing a tutorial I saw a code piece, to understand this try to write a sample function and call it.
since I am new to scala do not find where to start.
val flow3: Flow[Int, Int, NotUsed] = Flow[Int].statefulMapConcat {
() =>
var sequence = 0
println("statefulMapConcat func call")
i =>
sequence = sequence + i
List(sequence)
}
in the above two things are strange for me
() => why no parameter
() => and i => // are they parameter, what kind of style is this. which is calling actual function. and how we can write a function to call this
definition is :
def statefulMapConcat[T](f: () ⇒ Out ⇒ immutable.Iterable[T]): Repr[T] =
via(new StatefulMapConcat(f))
my tries!!
def suffix(x: String): String = x + ".zip"
// not sure this is true
def test1(f: String ⇒ String ⇒ String): String = f("a1")("a2") + "a3"
// not sure this is also a true definition
def test2(f: String ⇒ String ⇒ String): String = f + "a4"
// compile is okay but can not call this
var mytest= test1{
a => a + "a5"
b => b + "a6"
}
// giving even compile time error
test(suffix(suffix("")))
var mytest= test1{
a => a + "a5"
b => b + "a6"
}
In this examble you can't call mytest because "mytest" is not a function but result of "test1" function evaluation instead. "mytest" is a string value. So you can replace this code with the following and this would still compile:
var mytest: String= test1{
a => a + "a5"
b => b + "a6"
}
Your second example has another problem. You are truing to call "test" function passing result of evaluated "suffix(suffix(""))" which is string.
To make it compiles you need to create function that returning function and then pass it to "test"(1 or 2)
def functionReturiningFunciton(s:String):String=>String = (k) => suffix(suffix(""))
val f: String => String => String = functionReturiningFunciton // convert to value
test1(f)
test2(f)
or you can even pass "functionReturiningFunciton" directly, because it will be converted to val automatically
def functionReturiningFunciton(s:String):String=>String = (k) => suffix(suffix(""))
test1(functionReturiningFunciton)
test2(functionReturiningFunciton)
or even like this
test1(s => k => suffix(suffix("")))
Note. When you do this:
var mytest= test1{
a => a + "a5"
b => b + "a6"
}
If you de-sugar your code. You are actually doing this:
def someFunction(a:String):String=>String = {
a + "a5" // this is evaluated but ignored
b => b + "a6" //this is what returned by someFunction
}
var mytest:String= test1{someFunction}
definition is :
def statefulMapConcat[T](f: () ⇒ Out ⇒ immutable.Iterable[T]): Repr[T] =
via(new StatefulMapConcat(f))
Function statefulMapConcat takes as a parameter another function that has zero parameters and returns another function that takes parameter with type "Out" and returns Iterable[T]
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)
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))
}
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.