improvement-proposals icon indicating copy to clipboard operation
improvement-proposals copied to clipboard

SIP-63 - Scala 3 Macro Annotations

Open nicolasstucki opened this issue 1 year ago • 9 comments

nicolasstucki avatar Feb 20 '24 12:02 nicolasstucki

Please open a thread on contributors.scala-lang.org to gain community feedback, and link it to this proposal.

soronpo avatar Mar 08 '24 14:03 soronpo

Please open a thread on contributors.scala-lang.org to gain community feedback, and link it to this proposal.

Here is the contributors thread: https://contributors.scala-lang.org/t/scala-3-macro-annotations-sip-63-discussions/6593

nicolasstucki avatar Mar 08 '24 17:03 nicolasstucki

One question that came up in the last SIP meeting is whether or not it's possible to implement https://github.com/scala/improvement-proposals/pull/78 using macro annotations, and what it would look like if we did. @nicolasstucki do you have any insights there? We already have full implementations and test cases in the https://github.com/com-lihaoyi/unroll/ repo, so it should be possible to try it out using macro annotations and see if it can be made to work

lihaoyi avatar Mar 21 '24 04:03 lihaoyi

One question that came up in the last SIP meeting is whether or not it's possible to implement https://github.com/scala/improvement-proposals/pull/78 using macro annotations, and what it would look like if we did. @nicolasstucki do you have any insights there?

I wrote and example implementation of a strip down version of https://github.com/scala/improvement-proposals/pull/78 for unrolling the last parameters of a def. This implementation shows that we have access to all the we need to construct the definition new definition.

However, we still have some limitations in the current implementation, such as missing the parameter macro annotations (we are woking on a prototype and should have something soonish). We might also me missing some helper functions in the reflection API to help us deal with this transformation more elegantly (for example a simple way to get the default arguments).

I have not tried with constructors yet. We will have a similar situation for class constructors. But, case class constructors parameter unrolling might not fit the current specification of macro annotations. As the annotation is on the parameter, the transformed tree will be the constructor of the case class, this only allows us to add methods in the case class itself but not in the compassion object.

nicolasstucki avatar Mar 21 '24 10:03 nicolasstucki

@jchyb and @hamzaremmal will take over the development of this SIP.

nicolasstucki avatar Apr 30 '24 13:04 nicolasstucki

This proposal was discussed at the last SIP meeting, but there was concern that the current proposal is currently too limited and did not have enough usecases as-is:

  • The vote for accepting it lead to a 4/4 split.
  • The committee unanimously voted against rejecting the proposal.

In particular, the fact that existing libraries like cask and mainargs cannot be ported to work as-is without requiring extra annotations seems problematic. If we look at the cask example from @lihaoyi again:

// Cask
object MinimalApplication extends cask.MainRoutes{
  @cask.get("/")
  def hello() = {
    "Hello World!"
  }

  @cask.post("/do-thing")
  def doThing(request: cask.Request) = {
    request.text().reverse
  }

  initialize()
}

The current proposal would require an extra annotation on the object definition to gather all the method-level annotations.

To avoid this extra level of boilerplate, I'd like to suggest we introduce "inheritable macro annotation", concretely if we define MainRoutes in cask as:

class caskGen extends InheritableMacroAnnotation { ... }
@caskGen trait MainRoutes { ... }

Then we should desugar:

object MinimalApplication extends cask.MainRoutes

into:

@caskGen object MinimalApplication extends cask.MainRoutes

I believe inheritable macro-annotations could be useful in many situations. For example, if I want to memoize instances of an open class hierarchy, I'd like to be able to define:

class memo extends InheritableMacroAnnotation { ... }
@memo trait Base

so that anyone inheriting from Base automatically gets a memoized class without having to remember to put the annotation on the class.

smarter avatar May 15 '24 14:05 smarter