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?
With a macro, we can treat programs as values, which allows us to analyze and generate them at compile time. A Scala expression with type T is represented by an instance of the type scala.quoted.Expr [T].
As you've seen, you can extend existing classes in Scala using implicit conversions. To implement this recipe of adding new functionality to existing classes, you: Create a new class that contains the new method (s) you want. In my case I added the increment method to the String class.
A cool thing about implicit conversions in Scala is that they let you add new methods to existing classes, including existing Java and Scala classes such as String, File, and so on.
Both in Scala IDE and in Intellij IDEA macros are known to work fine, given they are moved to a separate project. Debugging macros (i.e. the logic that drives macro expansion) is fairly straightforward. Since macros are expanded within the compiler, all that you need is to run the compiler under a debugger.
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.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With