1

I was taking a look at the source code of sjson when I discovered this weird piece of code:

<#list 2..22 as i> 
<#assign typeParams><#list 1..i as j>T${j}<#if i !=j>,</#if></#list></#assign>

  def asProduct${i}[S, ${typeParams}](<#list 1..i as j>f${j}: String<#if i != j>,</#if></#list>)(apply : (${typeParams}) => S)(unapply : S => Product${i}[${typeParams}])(implicit <#list 1..i as j>bin${j}: Format[T${j}]<#if i != j>,</#if></#list>) = new Format[S]{
    def writes(s: S) = {
      val product = unapply(s)
      JsObject(
        List(
          <#list 1..i as j>
          (tojson(f${j}).asInstanceOf[JsString], tojson(product._${j}))<#if i != j>,</#if>
          </#list>
        ))
    }
    def reads(js: JsValue) = js match {
      case JsObject(m) => // m is the Map
        apply(
          <#list 1..i as j>
          fromjson[T${j}](m(JsString(f${j})))<#if i != j>,</#if>
          </#list>
        )
      case _ => throw new RuntimeException("object expected")
    }
  }  
  </#list>

At first sight, it looks like a macro but I'm not sure because the ones I have seen are different and they modify Scala AST using classes like WeakTypeTag and so on. I know that this method is generating asProduct methods with 20 different parameters list. However, when I copy this piece of code in my REPL it's not parsed correctly and I get the following error:

<console>:1: error: identifier expected but double literal found.

And a pile of more errors.

I would like to know:

  • Why and how this method works
  • More resources to learn to master this
  • Why in other libraries they don't use it and they prefer to copy/paste the methods manually (is there actually a reason for this or maybe they don't know its existence?)
Jorge
  • 784
  • 4
  • 17
  • 1
    At a glance I'd guess that these are FMPP directives being used for code generation. Scala macros don't add new syntax (okay, only a little, via the `macro` keyword). – Travis Brown Apr 08 '15 at 18:47

1 Answers1

3

As comment suggested, sjson uses FMPP templates to generate scala files. You can find how it's done in the projects build:

https://github.com/debasishg/sjson/blob/master/project/SJsonProject.scala#L61-L86

So it has nothing to do with scala macros feature.

In my experience most projects, that need this kind of code generation, use some library or SBT plugin for this.

An alternative to FMPP approach would be to use SBT plugin. I personally prefer sbt-boilerplate plugin. It's easy to use and requires less code in the template. But it's still template-based approach for code genration.

tenshi
  • 26,268
  • 8
  • 76
  • 90
  • Thanks for the pointers, I will use sbt-boilerplate, it looks better than FMPP templates. – Jorge Apr 09 '15 at 07:55