What can you do with MacroAnnotaiton that you cannot do with Macros in Scala 3?
Asked Answered
G

1

2

Scala 3.3.0-RC2 has added MacroAnnotation but it has a ton of caveats. The main on is that "new definitions will not be visible from outside the macro expansion".

There are a lot of examples in https://github.com/lampepfl/dotty/tree/main/tests/run-macros (the ones starting with annot-). Some of these examples are demonstrated in this answer.

It seems that these are completely blackbox (apart from a structural type trick). All they can really do is modify/override an existing definition.

I thought that you can do already do the same thing by overriding/wrapping a definition with a Macro.

What is it that you can do with a MacroAnnotation that you cannot do with a Macro?

Gonocyte answered 13/4, 2023 at 2:39 Comment(0)
O
2

You're right,

are not so interesting because new definitions are not visible from outside the macro expansion. These annotations are just examples how to write macro annotations in Scala 3. To make them interesting, new definitions should be used in some way inside the macro expansion.

But look at @memoize and @equals from Macro Annotations in Scala 3. They are more interesting because new definitions are actually used inside the macro expansion. So sometimes macro annotations can be useful in Scala 3. Although in Scala 3 macro annotations are indeed much more restrictive than those in Scala 2 (and macros generally are more restrictive in Scala 3 than in Scala 2 e.g. there are no c.eval, c.parse, quasiquotes etc.). So code generation with Scalameta (and Semanticdb), Scalafix, compiler plugins etc. are still necessary in cases when macros or macro annotations are not enough. You can read discussion in https://contributors.scala-lang.org/t/scala-3-macro-annotations-and-code-generation/6035 with motivation why to introduce macro annotations in Scala 3. A quote from there:

@odersky:

I believe the way it is intended, a macro annotation can check that a class conforms to a certain schema, but cannot generate definitions that makes it conform. So if the macro gets updated, the new check might fail and another action to fix it might be proposed.

It’s similar to @tailrec. No magic, just an assertion that the annotated construct has certain properties.


I thought that you can do already do the same thing by overriding/wrapping a definition with a Macro.

What is it that you can do with a MacroAnnotation that you cannot do with a Macro?

Well, that's the thing that you do not need to define a new macro wrapper every time you want to instrument another definition, it's enough to annotate it with the same macro annotation.


Moreover, new definitions are not visible from outside the macro expansion statically. In bytecode they are present. You can call them with runtime reflection. For example for @mainMacro from Macro Annotations in Scala 3

import Macros.mainMacro
import scala.annotation.experimental

@experimental
object App:
  @mainMacro def Test(): Unit = println("macro generated main")

//scalac: List(class Test extends java.lang.Object {
//  def main(args: scala.Array[scala.Predef.String]): scala.Unit = App.Test()
//}, @Macros.mainMacro def Test(): scala.Unit = scala.Predef.println("macro generated main"))
// new App.Test().main(Array[String]()) // doesn't compile: type Test is not a member of object App

val clazz = Class.forName("App$Test")
clazz.getMethod("main", classOf[Array[String]])
  .invoke(clazz.newInstance(), Array[String]())
// macro generated main
Oren answered 13/4, 2023 at 7:57 Comment(2)
You can use new definitions inside macro defs too can't you? You are right about the memoize case, that is something that cannot be done with a macro def because you need that definition to live outside of the method call so that there is a place to store the memoized value. Apart from that, the other cases seem like a very minor convenience improvement.Gonocyte
contributors.scala-lang.org/t/pre-sip-export-macros/6168 github.com/littlenag/dotty/tree/export-macro gist.github.com/littlenag/d0c9dfddeb9002684c6effef18c2ec5eOren

© 2022 - 2024 — McMap. All rights reserved.