seand
seand

Reputation: 5286

Understanding a Scala function from Play framework zentask example

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))
}

Upvotes: 4

Views: 630

Answers (2)

huynhjl
huynhjl

Reputation: 41646

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)

Upvotes: 1

Shadowlands
Shadowlands

Reputation: 15074

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 _)

Upvotes: 3

Related Questions