What does the word โ€œActionโ€ do in a Scala function definition using a playback platform?

I am developing a Play application and I was just starting out with Scala. I see that there is this word Action after the equal sign in the function below and before the brace.

 def index = Action { Ok(views.html.index("Hi there")) } 

What does this code do? I saw that it was used with def index = { , but not with the word before the brace.

I would suggest that the function name is index . But I do not know what the word Action does in this situation.

+8
scala playframework
source share
3 answers

Other answers relate to your specific case. However, you asked about the general case, so I will try to answer from this point of view.

Firstly, def used to determine the method of a non- function (it is better to know this difference now). But, you are right, index is the name of this method.

Now, unlike other languages โ€‹โ€‹that may be familiar with (for example, C, Java), Scala allows you to define methods with an expression (as suggested by the syntax of the assignment operator, = ). That is, everything after = is an expression that will be evaluated to a value each time the method is called.

So, while in Java you should say:

 public int three() { return 3; } 

In Scala, you can simply say:

 def three = 3 

Of course, the expression is usually more complex (as in your case). It may be a block of code, for example, you are more used to seeing, in which case this value has the meaning of the last expression in the block:

 def three = { val a = 1 val b = 2 a + b } 

Or it may include a method call for another object:

 def three = Numbers.add(1, 2) 

The latter, in fact, is exactly what happens in your particular example, although this requires a bit more explanation. The game involves two parts of magic:

  • If the object has an apply method, then you can treat the object as if it were a function. You can say, for example, Add(1, 2) when you really mean Add.apply(1,2) (assuming the Add object with the apply method, of course). And in order to be understandable, it should not be an object defined using the keyword object . Any object with a suitable apply method will do.
  • If the method has one by-name parameter (for example, def ifWaterBoiling(fn: => Tea) ), you can call a method like ifWaterBoiling { makeTea } . The code in this block is evaluated lazily (and may not be evaluated at all). This would be equivalent to writing ifWaterBoiling({ makeTea }) . The { makeTea } simply defines the expression that is passed, not evaluated, for the fn parameter.
+9
source share

This word is part of the Play Framework and object , which has an apply(block: โ‡’ Result) method, so your code is actually:

 def index: Action[AnyContent] = Action.apply({ Ok.apply(views.html.index("Hi there")) }) 

Your index method returns an instance of class Action[AnyContent] .

By the way, you pass the code block {Ok(...)} to the apply method, which (the code block) actually acts as an anonymous function here, because the required type to apply not just Result , but โ‡’ Result , which means that it accepts an anonymous function without input parameters, which returns Result . Thus, your Ok-block will be executed when the container received by your Action class instance (from the index method) decided to execute this block. It just means that you are simply describing the action here โ€” not doing it โ€” it will actually be executed when Play received your request โ€” and find the binding to your action in the routing file.

In addition, you do not need to use def here, since you always return the same action - usually val or lazy val . You will need def only if you really want to pass some parameter from the routing table (for example):

 GET /clients/:id controllers.SomeController.index(id: Long) def index(id: Long) = Action { ... } // new action generated for every new request here 

Another possible approach is to select an Action based on a parameter:

 def index(id: Long) = { if (id == 0) Action {...} else Action{...} } 

But uasually you can use a routing table for this, which is better for decoupling. This example shows that Action is nothing more than a return value.


Update for @Kazuya

  val method1 = Action{...} //could be def too, no big difference here // this (code inside Action) gonna be called separately after "index" (if method2 is requested of course) // notice that it needs the whole request, so it (request) should be completely parsed at the time val method2 = Action{ req => // you can extract additional params from request val param1 = req.headers("header1") ... } //This is gonna be called first, notice that Play doesn't need the whole request body here, so it might not even be parsed on this stage def index(methodName: String) = methodName match { case "method1" => method1 case "method2" => method2 } 

GWT / Scala.js uses the simillar approach for client-server interaction. This is just one possible solution to explain the importance of the methodName parameter passed from the routing table. Thus, an action can be considered as a wrapper over a function, which, in turn, is a reference to the OOP method, which makes it useful for both REST and RPC purposes.

+14
source share

The Action property is called with an expression block as an argument. (The apply method is used under the hood.)

 Action.apply({ Ok("Hello world") }) 

A simple example (from here ) is as follows (see comments in the code):

 case class Logging[A](action: Action[A]) extends Action[A] { def apply(request: Request[A]): Result = {// apply method which is called on expression Logger.info("Calling action") action(request) // action being called on further with the request provided to Logging Action } lazy val parser = action.parser } 

Now you can use it to transfer any other action value:

 def index = Logging { // Expression argument starts Action { // Action argument (goes under request) Ok("Hello World") } } 

Also, the case you mentioned for def index = { actually returns Unit as: def index: Unit = { .

+4
source share

All Articles