5

I'm new to scala macros and I'm using scala 2.10.0-RC3.

I want to write a macro that adds a function to a class. Usage example:

trait MyTrait {
  def addF = macro { /*add "def f = 3" to class*/ }
}

class MyClass extends MyTrait {
  addF //Adds the "def f" to MyClass
}

object Main {
  val t = new MyClass
  assert(t.f==3)
}

I need this in the following scenario. My first try didn't use macros but didn't work, because I can't inherit the same trait twice.

trait AddF[T] {
  def f(t: T) { /* ...do sthg ... */ }
}

class MyClass extends AddF[Int] with AddF[String]

With the macro solution I could write

class MyClass extends MyTrait {
  addF[Int]()
  addF[String]()
}

Is there a way to do this with scala macros? Or is there another way to achieve this?

Heinzi
  • 5,793
  • 4
  • 40
  • 69
  • 1
    I'm just wondering: Do you want `f` to take any parameter or not? If it does, wouldn't it be more appropriate to solve this for instance by type annotations for `f` itself? – bluenote10 Nov 29 '12 at 16:45
  • It should later be possible to call both f from the two-function example. The easiest way I thought of was using a parameter MyClass.f(3) vs. MyClass.f("bla"). If there is a way that I later could write MyClass.f[String] vs MyClass.f[Int] (but not MyClass.f[Double], because that wasn't defined), this would also be ok. What do you mean by type annotations for f itself? – Heinzi Nov 29 '12 at 16:50
  • Hm, wouldn't it be possible in this case to just overload the function with the respective types? So just one `f(i: Int) { ... }` and one `f(s: String) { ... }`? – bluenote10 Nov 29 '12 at 17:05
  • This would work, but the f function is complex and I need it in many places. So I want to avoid this boilerplate and have a shorthand for it - e.g. a macro inserting the function into a class. – Heinzi Nov 29 '12 at 17:50

2 Answers2

8

It is currently impossible to add, modify or remove definitions visible outside the macro. I.e. you can create a class or a method local to the expansion (e.g. emit a ClassDef tree as a part of the result returns by your macro), but there's no facility to affect the outside world.

However we plan to experiment with this functionality as roughly sketched in http://scalamacros.org/future.html. Also there's already a solid prototype that can generate new top-level classes. Contact me for details if you would like to take a look.

Eugene Burmako
  • 13,028
  • 1
  • 46
  • 59
  • As it stands now, you should be able to generate a new class (using c.introduceTopLevel) Is there, however, a way to add, modify or remove on an existing implementation outside of the macro? – Daniel Macias Jun 09 '13 at 19:57
  • No there is not, though we're working on something like that. Hard to say what will pan out though – Eugene Burmako Jun 10 '13 at 11:03
  • Any news on this topic as of Scala 2.11? – Haspemulator Jun 19 '15 at 08:16
  • The most relevant (but still not quite sufficient) functionality in Scala can be achieved with Scala 2.10/2.11 and the macro paradise plugin: http://docs.scala-lang.org/overviews/macros/annotations.html. – Eugene Burmako Jun 20 '15 at 08:41
1

In case I'm not completely confused, simple overloading should provide the desired behavior? For instance, this would work:

trait MyTrait {
  def f(i: Int)
  def f(i: String)
}

class MyClass extends MyTrait {
  def f(i: Int) {
    println(i + " was an Int")
  }
  def f(s: String) {
    println(s + " was a String")
  }
}

// this allows:
val c = new MyClass()
c.f("hello")
c.f(42)
bluenote10
  • 23,414
  • 14
  • 122
  • 178
  • 3
    That's exactly the result I want the macro to generate. I don't want to write this code on my own, because I need the same f function in many classes (but each time possibly with different type parameters). – Heinzi Nov 29 '12 at 18:08