0

Can Scala macros be used to make implementers of a method in a trait invoke the super method. For instance like this:

trait Super {
  //some macro magic here: list = super.list ++ child.list
  def list: List[String] = List("ein", "zwei", "DIE")
}

class Sub extends Super {
  override def list: List[String] = List("4", "5")
}

object Testy extends App {
  println(new Sub().list) //List(ein, zwei, DIE, 4, 5)
}

Update: See comment from @Sergey below - this is not really doable with macros.

eirirlar
  • 814
  • 6
  • 24

1 Answers1

1

I don't think you need macros in this particular case. In order to enforce some data from a superclass' method to be added to all results of implementing methods in any subclass, the preferred approach would be to use a template method. Make a final def performing the addition of the fixed part and an abstract def declaring the variable part, like so:

trait Super {
  protected def additionalList: List[String]
  final def list: List[String] = List("ein", "zwei", "DIE") ++ additionalList
}

class Sub extends Super {
  protected val additionalList = List("4", "5")
}

object Testy extends App {
  println(new Sub().list) // List(ein, zwei, DIE, 4, 5)
}

Update: If, however, you need exactly the behavior as specified in the original question, then you're out of luck, I fear: a macro can only affect what it immediately wraps, e.g. a def macro can only transform what is passed into the method, and an annotation macro can only transform its immediate annottee, be it a class, a field, a method, etc. There's no way for a macro to enforce rules on code which doesn't even know about the macro. So basically you have two options: either make your users call super manually, or write an annotation macro and have your users annotate their subclasses with it. Both of these options are easy to omit, unfortunately.

Sergey
  • 2,880
  • 3
  • 19
  • 29
  • Creative approach, but Sub needs to be able implement the list function for my use case as this is what the programmers that implement Super will expect to work. – eirirlar May 24 '16 at 15:54
  • Then you're out of luck on this case, I fear: a macro can only affect what it immediately wraps, e.g. a def macro can only transform what is passed into the method, and an annotation macro can only transform the literal it annotates, be it class, field, whatever; there's no way for a macro to enforce rules on code which doesn't even know about the macro. So basically you have two options: either make your users call `super` manually, or write an annotation macro and have your users annotate their subclasses with it. Both of them are easy to omit, unfortunately. – Sergey May 24 '16 at 18:41
  • Thanks for the clarification. This comment sounds like the answer to the question. If you post as answer I'll accept. I ended up writing in the doc that clients need to call super and prepend results to their own implementation. – eirirlar May 26 '16 at 09:36
  • Nevermind re-answering, I'll just accept your answer. – eirirlar May 26 '16 at 09:38