I have a parameterized class like
class Test[T]{
//...
}
object Test{
implicit def materializeTest[T]: Test[T] = macro impl[T]
def impl[T: c.WeakTypeTag](c: blackbox.Context) = //...
}
If using the materialized implicit from the same module it throws an error:
macro implementation not found
But the problem is extracting a single class into a separate module looks absolutely ugly and cumbersome. Maybe there is some "well-known workaround" to avoid that? Maybe shapeless can be helpful here?
UPD:
scalaVersion in ThisBuild := "2.13.2"
Here is my minimal example:
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
object Main {
sealed trait Adt
case object Adt1 extends Adt
case object Adt2 extends Adt
trait Test[Adtt <: Adt] {
def restrict(restrictions: List[Int]): List[Int]
}
object Test {
def apply[Adtt <: Adt](implicit ev: Test[Adtt]): Test[Adtt] = ev
implicit def implicitMaterializer[
Adtt <: Adt
]: Test[Adtt] = macro impl[Adtt]
def impl[Adtt <: Adt: c.WeakTypeTag](
c: blackbox.Context
): c.Expr[Test[Adtt]] = {
import c.universe._
c.Expr[Test[Adtt]](q"""???""")
}
}
def main(args: Array[String]): Unit = {
Test[Adt1.type].restrict(List(1, 2, 3))
}
}
which results in the following error:
[error] Main.scala:32:9: macro implementation not found: implicitMaterializer
[error] (the most common reason for that is that you cannot use macro implementations in the same compilation run that defines them)
You can extract to a separate module not Test but TestMacro
core
import scala.language.experimental.macros
class Test[T]
object Test {
implicit def materializeTest[T]: Test[T] = macro TestMacro.impl[T]
}
implicitly[Test[Int]] // compiles
macros
import scala.reflect.macros.blackbox
object TestMacro {
def impl[T: c.WeakTypeTag](c: blackbox.Context) = {
import c.universe._
q"new Test[${weakTypeOf[T]}]"
}
}
Ugly or not but macro implementations must be compiled before they are applied (but Is there any trick to use macros in the same file they are defined?).
This is improved in Scala 3
http://dotty.epfl.ch/docs/reference/metaprogramming/macros.html#defining-a-macro-and-using-it-in-a-single-project
Shapeless just hides some predefined set of standard macros, it can't help with your own macros.
Related
I'm trying to solve a problem that may not be possible in Scala.
I want to have a Trait to solve default constructors
trait Builder[T <: Buildable] {
def build(code: String): T = new T(code)
def build: T = new T("bar")
}
So extending the Trait on the companion object automatically has access to functions that creates the class with specific constructors and parameters
class A(code: String) extends Buildable
object A extends Builder[A]
Extending the Trait, the companion object has the constructors
A.build("foo")
A.build
Is this possible in Scala?
Also tried abstract classes, but hadn't had any success
trait Builder[T <: BuildableClass] {
def build(code: String): T = new T(code)
def build: T = new T("bar")
}
abstract class BuildableClass(code: String)
class A(code: String) extends BuildableClass(code)
object A extends Builder[A]
Thanks in advance
Edit: currently locked on Scala 2.12
Because of the type erasure, in ordinary code new T is allowed only for class type T, not an abstract type/type parameter.
In Scala, is it possible to instantiate an object of generic type T?
How to create an instance of type T at runtime with TypeTags
Class type required but T found
An alternative to runtime reflection (see #StanislavKovalenko's answer) is macros. new T is possible there because during macro expansion T is not erased yet.
import scala.language.experimental.macros
import scala.reflect.macros.blackbox // libraryDependencies += scalaOrganization.value % "scala-reflect" % scalaVersion.value
abstract class BuildableClass(code: String)
trait Builder[T <: BuildableClass] {
def build(code: String): T = macro BuilderMacros.buildImpl[T]
def build: T = macro BuilderMacros.buildDefaultImpl[T]
}
class BuilderMacros(val c: blackbox.Context) {
import c.universe._
def buildImpl[T: WeakTypeTag](code: Tree): Tree = q"new ${weakTypeOf[T]}($code)"
def buildDefaultImpl[T: WeakTypeTag]: Tree = q"""new ${weakTypeOf[T]}("bar")"""
}
// in a different subproject
class A(code:String) extends BuildableClass(code)
object A extends Builder[A]
A.build("foo") // scalac: new A("foo")
A.build // scalac: new A("bar")
Alternative implementations:
trait Builder[T <: BuildableClass] {
def build(code: String): T = macro BuilderMacros.buildImpl
def build: T = macro BuilderMacros.buildDefaultImpl
}
class BuilderMacros(val c: blackbox.Context) {
import c.universe._
val tpe = c.prefix.tree.tpe.baseType(symbolOf[Builder[_]]).typeArgs.head
def buildImpl(code: Tree): Tree = q"new $tpe($code)"
def buildDefaultImpl: Tree = q"""new $tpe("bar")"""
}
class BuilderMacros(val c: blackbox.Context) {
import c.universe._
val symb = c.prefix.tree.symbol.companion
def buildImpl(code: Tree): Tree = q"new $symb($code)"
def buildDefaultImpl: Tree = q"""new $symb("bar")"""
}
class BuilderMacros(val c: blackbox.Context) {
import c.universe._
val tpe = c.prefix.tree.tpe.companion
def buildImpl(code: Tree): Tree = q"new $tpe($code)"
def buildDefaultImpl: Tree = q"""new $tpe("bar")"""
}
class BuilderMacros(val c: blackbox.Context) {
import c.universe._
val tpe = symbolOf[Builder[_]].typeParams.head.asType.toType
.asSeenFrom(c.prefix.tree.tpe, symbolOf[Builder[_]])
def buildImpl(code: Tree): Tree = q"new $tpe($code)"
def buildDefaultImpl: Tree = q"""new $tpe("bar")"""
}
One of the potential solution that uses a reflection looks a bit ugly, but it works.
import scala.reflect._
trait Builder[T <: Buildable] {
def build(code: String)(implicit ct: ClassTag[T]): T =
ct.runtimeClass.getConstructors()(0).newInstance(code).asInstanceOf[T]
def build(implicit ct: ClassTag[T]): T =
ct.runtimeClass.getConstructors()(0).newInstance("bar").asInstanceOf[T]
}
trait Buildable
class A(code: String) extends Buildable {
def getCode = code
}
object A extends Builder[A]
val a: A = A.build
println(a.getCode)
The problem is that your Builder trait doesn't know anything about how to construct your instances. You can get this info from runtime with reflection or from compile time with macros.
Found a much cleaner solution to this problem without using macros / reflection / implicits
trait Buildable
trait Builder[T <: Buildable] {
self =>
def apply(code: String): T
def build: T = self.apply("foo")
def build(code: String): T = self.apply(code)
}
case class A(code: String) extends Buildable {
def getCode: String = code
}
object A extends Builder[A]
A.build("bar").getCode
A.build.getCode
Consider a trait that performs "encoding" of arbitrary objects:
trait Encoder[R] {
def encode(r: R): Array[Byte]
}
Assuming encoding of primitive types is known and custom types can be encoded by defining up a "serializer":
trait Serializer[T] {
def serialize(r: T): Array[Byte]
}
we can implement a macro for case class encoding by simply looping the fields and looking up type serializers implicitly. Here's a dummy implementation that looks up the serializer for R itself (in reality we look up serializers for case class field types):
object Encoder {
implicit def apply[R <: Product]: Encoder[R] = macro applyImpl[R]
def applyImpl[R: c.WeakTypeTag](c: blackbox.Context): c.Expr[Encoder[R]] = {
import c.universe._
c.Expr[Encoder[R]](q"""
new ${weakTypeOf[Encoder[R]]} {
override def encode(r: ${weakTypeOf[R]}): Array[Byte] =
implicitly[_root_.Serializer[${weakTypeOf[R]}]].serialize(r)
}
""")
}
}
Now define a base "processor":
abstract class BaseProcessor[R: Encoder] {
def process(r: R): Unit = {
println(implicitly[Encoder[R]].encode(r).length)
}
}
And try to use it:
case class Record(i: Int)
object Serializers {
implicit def recordSerializer: Serializer[Record] =
(r: Record) => Array.emptyByteArray
}
import Serializers._
class Processor extends BaseProcessor[Record]
This fails to compile with:
// [error] Loader.scala:10:22: could not find implicit value for parameter e: Serializer[Record]
// [error] class Processor extends BaseProcessor[Record]
// [error] ^
// [error] one error found
However the following do compile:
class Processor extends BaseProcessor[Record]()(Encoder[Record]) // Compiles!
object x { class Processor extends BaseProcessor[Record] } // Compiles!
I can't really understand why this happens, looks like it has something to do with the Processor definition being a top level definition, since as soon as I move it inside a class/object everything works as expected. Here's one more example that fails to compile:
object x {
import Serializers._ // moving the import here also makes it NOT compile
class Processor extends BaseProcessor[Record]
}
Why does this happen and is there any way to make it work?
To make it work you can try one of the following:
1) add context bound
implicit def apply[R <: Product : Serializer]: Encoder[R] = macro applyImpl[R]
def applyImpl[R: c.WeakTypeTag](c: blackbox.Context)(serializer: c.Expr[Serializer[R]]): c.Expr[Encoder[R]] = {
import c.universe._
c.Expr[Encoder[R]](q"""
new Encoder[${weakTypeOf[R]}] {
override def encode(r: ${weakTypeOf[R]}): Array[Byte] =
$serializer.serialize(r)
}
""")
}
2) make macro whitebox
3) put implicit instance recordSerializer: Serializer[Record] to the companion object of Record rather than some object Serializers to be imported
4) maybe your example is easier than actual use case but now it seems you don't need macros
implicit def apply[R <: Product : Serializer]: Encoder[R] = new Encoder[R] {
override def encode(r: R): Array[Byte] = implicitly[Serializer[R]].serialize(r)
}
The use cases for implicit macros is supposed to be the so-called "materialisation" of type class instances.
Unfortunately, the example in the documentation is a bit vague on how that is achieved.
Upon being invoked, the materializer can acquire a representation of T and generate the appropriate instance of the Showable type class.
Let's say I have the following trait ...
trait PrettyPrinter[T]{
def printed(x:T) : String
}
object PrettyPrinter{
def pretty[T](x:T)(implicit pretty:PrettyPrinter[T]) = pretty printed x
implicit def prettyList[T](implicit pretty :PrettyPrinter[T]) = new PrettyPrinter[List[T]] {
def printed(x:List[T]) = x.map(pretty.printed).mkString("List(",", ",")")
}
}
and three test classes
class A(val x:Int)
class B(val x:Int)
class C(val x:Int)
Now I understand that instead of writing the following boilerplate
implicit def aPrinter = new PrettyPrinter[A] {def printed(a:A) = s"A(${a.x})"}
implicit def bPrinter = new PrettyPrinter[B] {def printed(b:B) = s"B(${b.x})"}
implicit def cPrinter = new PrettyPrinter[C] {def printed(c:C) = s"C(${c.x})"}
we should be able to add
implicit def materialise[T] : PrettyPrinter[T] = macro implMaterialise[T]
def implMaterialise[T](c:blackbox.Context):c.Expr[PrettyPrinter[T]] = {
import c.universe._
???
}
to the object PrettyPrinter{...} which then generates the corresponding PrettyPrinters on demand ... how? How do I actually get that "representation of T"?
If I try c.typeOf[T], for example, "No TypeTag available for T".
UPDATE
Trying to use class tags doesn't seem to work either.
implicit def materialise[T:ClassTag] : PrettyPrinter[T] = macro implMaterialise[T]
def implMaterialise[T:ClassTag](c:blackbox.Context):c.Expr[PrettyPrinter[T]] = {
import c.universe._
???
}
results in
Error:(17, 69) macro implementations cannot have implicit parameters other than WeakTypeTag evidences
implicit def materialise[T:ClassTag] : PrettyPrinter[T] = macro implMaterialise[T]
^
update2
Interestingly, using WeakTypeTags doesn't really change anything as
implicit def materialise[T:WeakTypeTag]: PrettyPrinter[T] = macro implMaterialise[T]
def implMaterialise[T](c:blackbox.Context)(implicit evidence : WeakTypeTag[T]):c.Expr[PrettyPrinter[T]]
= {
import c.universe._
???
}
will result in
Error:(18, 71) macro implementations cannot have implicit parameters other than WeakTypeTag evidences
implicit def materialise[T:WeakTypeTag]: PrettyPrinter[T] = macro implMaterialise[T]
^
How do I actually get that "representation of T"?
You need to use c.WeakTypeTag, as hinted at by the compiler message you found in your "UPDATE" section.
This project has a working example that you can adapt: https://github.com/underscoreio/essential-macros/blob/master/printtype/lib/src/main/scala/PrintType.scala
object PrintTypeApp extends App {
import PrintType._
printSymbol[List[Int]]
}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
import scala.util.{ Try => ScalaTry }
object PrintType {
// Macro that generates a `println` statement to print
// declaration information of type `A`.
//
// This only prints meaningful output if we can inspect
// `A` to get at its definition:
def printSymbol[A]: Unit =
macro PrintTypeMacros.printTypeSymbolMacro[A]
}
class PrintTypeMacros(val c: Context) {
import c.universe._
def printTypeSymbolMacro[A: c.WeakTypeTag]: c.Tree =
printSymbol(weakTypeOf[A].typeSymbol, "")
}
This is a follow-up to my previous question:
Suppose I create the following test converter.scala:
trait ConverterTo[T] {
def convert(s: String): Option[T]
}
object Converters {
implicit val toInt: ConverterTo[Int] =
new ConverterTo[Int] {
def convert(s: String) = scala.util.Try(s.toInt).toOption
}
}
class A {
import Converters._
def foo[T](s: String)(implicit ct: ConverterTo[T]) = ct.convert(s)
}
Now when I tried to call foo in REPL it fails to compile:
scala> :load converter.scala
Loading converter.scala...
defined trait ConverterTo
defined module Converters
defined class A
scala> val a = new A()
scala> a.foo[Int]("0")
<console>:12: error: could not find implicit value for parameter ct: ConverterTo[Int]
a.foo[Int]("0")
^
import Converters._ in class A does not cut it. You can remove it and the code will still compile. The moment the compiler needs to find in actual implicit is not in class A, where foo is just declared.
The compiler needs to find a ConverterTo[Int] in implicit scope at the moment you call a.foo[Int](..) that is in the REPL. So this is where the import needs to be.
Had object Converters and trait ConverterTo been named the same (so there would be a companion object) the import would not be needed.
The following macro is pasted from http://docs.scala-lang.org/overviews/quasiquotes/usecases.html:
import reflect.macros.Context
import language.experimental.macros
val universe = reflect.runtime.universe; import universe._
import reflect.runtime.currentMirror
import tools.reflect.ToolBox
val toolbox = currentMirror.mkToolBox()
object debug {
def apply[T](x: =>T): T = macro impl
def impl(c: Context)(x: c.Tree) = { import c.universe._
val q"..$stats" = x
val loggedStats = stats.flatMap { stat =>
val msg = "executing " + showCode(stat)
List(q"println($msg)", stat)
}
q"..$loggedStats"
}
}
It produces this error message in Scala 2.11.1:
Q.scala:9: error: macro implementation reference has wrong shape. required:
macro [<static object>].<method name>[[<type args>]] or
macro [<macro bundle>].<method name>[[<type args>]]
def apply[T](x: =>T): T = macro impl
^
I've tried varying the code in numerous ways (import reflect.macros.whitebox.Context, import reflect.macros.blackbox.Context, putting scala. at the start of each import, making the arguments consistently by-name or consistently by-value, macro impl[T], getting rid of the type parameter, macro debug.impl, putting the apply after the impl, and more) with no success. What am I doing wrong? Is it something in the imports? Those come (mostly) from a different web page, http://docs.scala-lang.org/overviews/quasiquotes/setup.html.
The same error occurs on both of the other example macros from that page:
object Macro {
def apply(x: Int): Int = macro impl
def impl(c: Context)(x: c.Expr[Int]): c.Expr[Int] = { import c.universe._
c.Expr(q"$x + 1")
}
}
object Macro {
def apply(x: Int): Int = macro impl
def impl(c: Context)(x: c.Tree) = { import c.universe._
q"$x + 1"
}
}
scala Foo.scala wraps the code that you feed to it in an anonymous class. As a result, something like:
import scala.reflect.macros.Context
import scala.language.experimental.macros
object debug {
def apply[T](x: T): T = macro impl
def impl(c: Context)(x: c.Tree): c.Tree = ???
}
Gets transformed into:
[[syntax trees at end of parser]] // Test.scala
package <empty> {
object Main extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
def main(args: Array[String]): scala.Unit = {
final class $anon extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
import scala.reflect.macros.Context;
import scala.language.experimental.macros;
object debug extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
<macro> def apply[T](x: T): T = impl;
def impl(c: Context)(x: c.Tree): c.Tree = $qmark$qmark$qmark
}
};
new $anon()
}
}
}
However, macro implementations must be defined in static object or bundles, which is what the error messages tries to say:
/Users/xeno_by/Projects/211x/sandbox/Test.scala:5: error: macro implementation reference has wrong shape. required:
macro [<static object>].<method name>[[<type args>]] or
macro [<macro bundle>].<method name>[[<type args>]]
def apply[T](x: T): T = macro impl
^
one error found
Unfortunately, if something is put into inside an anonymous class, it's no longer static, which means that scala Foo.scala-style development is incompatible with macros. Consider using alternatives, e.g. scalac or sbt.