Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play template only works when called with parentheses

I have the following code in my Application controller:

  def index = Action {
    var ticketsAvailable = 1
    Ok(views.html.index)
  }

When I try to run the application, I get this compilation error:

Cannot write an instance of views.html.index.type to HTTP response. Try to define a Writeable[views.html.index.type]

On the line

Ok(views.html.index) 

However, when I add parentheses (as shown below), the error disappears:

Ok(views.html.index()) 

Why is that? I thought that, in Scala, the usage of parentheses is optional when there are no arguments.

like image 577
octavian Avatar asked Mar 14 '23 00:03

octavian


1 Answers

It might be instructive to look at the generated Scala code for a simple Twirl template (Twirl is the Play templating engine) called index.scala.html:

@()

<h1>Hello, world</h1>

By default, Play will compile this to a Scala file in target/scala-2.11/twirl/main/views/html/index.template.scala, and, if you clean it up a bit to remove source mappings (which enable compile errors in templates to be translated to the right line in the input file) it will look something like this:

package views.html
import play.twirl.api._

object index_Scope0 {
  import models._
  import controllers._
  import play.api.i18n._
  import views.html._
  import play.api.templates.PlayMagic._
  import play.api.mvc._
  import play.api.data._

  class index
    extends BaseScalaTemplate[play.twirl.api.HtmlFormat.Appendable, Format[play.twirl.api.HtmlFormat.Appendable]](play.twirl.api.HtmlFormat)
    with play.twirl.api.Template0[play.twirl.api.HtmlFormat.Appendable] {

    def apply(): play.twirl.api.HtmlFormat.Appendable = {
      _display_ {
        {
          Seq[Any](format.raw(""""""), format.raw("""<h1>hello, world</h1>"""))
        }
      }
    }

    def render(): play.twirl.api.HtmlFormat.Appendable = apply()
    def f: (() => play.twirl.api.HtmlFormat.Appendable) = () => apply()
    def ref: this.type = this
  }
}

object index extends index_Scope0.index

The important thing to note is that views.html.index is an object, which has the type views.html.index.type, and that's what you refer to if you don't add parens. This object, however, extends a class called views.html.index_Scope0.index, which has an apply() method, which returns an Html object (or rather, HtmlFormat.Appendable, which is the unaliased type.)

If you "call" a Scala object, Scala translates (or "de-sugars") that to calling the apply() method on the object (which is how case class constructors work without using new.) Hence, if you use parens you get an Html object which is the result of the rendered Twirl template. If you don't, you just get the compiled template object itself, which Play doesn't know how to write to an HTTP response.

like image 59
Mikesname Avatar answered Mar 25 '23 04:03

Mikesname