Search code examples
scalamacrosnamed-parametersdefault-parameters

How can I get Scala Named and Default arguments to work with macros


Given scala version 2.11.7 and this macro definition:

import scala.language.experimental.macros
import scala.reflect.macros.whitebox.Context
package object macrotest {
  def namedMacro(c: Context)(a: c.Expr[Int]): c.Expr[Int] = {
    println("the int expr was " + a)
    a
  }
  def named(a: Int = 1) = macro namedMacro
}

And this invocation:

object NamedMacroTest {
  def main(args: Array[String]) {
    named()
    //named(a = 5) // or this
  }
}

Why do I see this error?

Error:(5, 10) macro applications do not support named and/or default arguments

And what can I do to not get the error, while still being able to call the macro with named and default arguments?


Solution

  • It was supposed to go back in, according to the 2.11 docs.

    The original issue was addressed in this PR which details the challenges.

    It was shot down finally at this attempt for technical reasons. They didn't like doing the desugaring and then losing what the original application looked like; and they didn't want to perform transforms and then have to undo it.

    One idea is to let adaptation take over when the arg is omitted:

    scala> :pa
    // Entering paste mode (ctrl-D to finish)
    
    def m[A: c.WeakTypeTag](c: Context)(i: c.Expr[A]): c.Expr[Int] = {
      import c.universe._
      if (i.tree.tpe <:< typeOf[Int]) i.asInstanceOf[c.Expr[Int]]
      else if (i.tree.tpe <:< typeOf[Unit]) c.Expr[Int](q"42")
      else c.abort(null,  "Nope") }
    
    // Exiting paste mode, now interpreting.
    
    m: [A](c: scala.reflect.macros.whitebox.Context)(i: c.Expr[A])(implicit evidence$1: c.WeakTypeTag[A])c.Expr[Int]
    
    scala> def f[A](i: A): Int = macro m[A]
    defined term macro f: [A](i: A)Int
    
    scala> f(1)
    res9: Int = 1
    
    scala> f()
    warning: there was one deprecation warning; re-run with -deprecation for details
    res10: Int = 42
    
    scala> f("")  // I don't remember where they keep NoPosition
    java.lang.NullPointerException
    

    It's easier just to do something different, like indirect through a method that takes an empty param list. Compare https://stackoverflow.com/a/25219644/1296806 and comments.