An introduction to the current state of Scala Macro

1. Macro scale

Scala Macro  is a new language feature added in Scala 2.10, allowing developers to dynamically modify/generate code during compilation, providing great flexibility for development work. The peak of Scala Macro development is the Scala 2.11 version, which adds more new features, the most dazzling of which is QUASIQUOTES , which can help developers shield the underlying details of the compiler and greatly simplify the macro writing work. As of Scala 2.12, Scala Macro has basically not changed much, and until now, Scala Macro has been labeled EXPERIMENTAL, which seems to be a bad sign. Sure enough, Scala Macro was finally abandoned by the official and replaced by is  reimplemented  in  Dotty and will be released in Scala 3.0 in 2020  . In fact, as early as March 17, 2018,  Eugene Burmako  , the core author of Scala Macro , has announced the abandonment of Scala Macro, and it seems that he is also preparing for Scala 3.0.

2. Meta scale

During the development of Scala Macro, another project ,  Scala Meta  , was derived. Originally, it was ambitious to replace the existing Scala Macro, but it went astray. Now the goal is to provide services for development tools. A typical derivative project is  Scalafmt , which can provide code formatting services for developers.

3. How are Scala Macros currently used?

Since Scala 2.11, Scala Macro has been merged into  Scala Reflect  , so just add Scala Reflect dependency to your project to start Macro development:

libraryDependencies += "org.scala-lang" % "scala-reflect" % "2.12.4"

The interesting thing is that the runtime Reflect and Macro share the underlying base API, which means that the two can interact through the underlying API. When developing Macro, Runtime Reflect can be used, for example:

import scala.reflect.macros.blackbox.Context
import scala.language.experimental.macros
import scala.reflect.runtime.{ universe => ru }

object Macros {
  def allClasses: List[String] = macro allClassesImpl
  def allClassesImpl(c: Context) = {
    import c.universe._

    val clsList =
      ru
        .runtimeMirror(this.getClass.getClassLoader)
        .staticPackage("models").typeSignature.decls
        .filter(s => s.isClass && s.asClass.isCaseClass)
        .map{ s =>
          s.asClass.typeSignature
          s.fullName
        }.toList

    q"$clsList"
  }
}

In the Macro method implementation, the class list under the models package can be read through the runtime universe. This is just an example to show that Scala Reflect's run time and compile time can work well together, but due to the JVM class loading mechanism, the above code doesn't actually work, and the list of classes read may be different for each run. In addition, when developing Macro, pay attention to the incremental compilation and hot loading of the build tool.

For more details, please refer to: official development documentation .

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325163977&siteId=291194637