Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scala macros: Add function to class

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?

like image 665
Heinzi Avatar asked Nov 29 '12 16:11

Heinzi


People also ask

What is the use of macro in Scala?

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].

How do I extend an existing class in Scala?

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.

What are implicit conversions in Scala?

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.

How do you debug macros in Scala IDE?

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.


2 Answers

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.

like image 55
Eugene Burmako Avatar answered Oct 21 '22 01:10

Eugene Burmako


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)
like image 1
bluenote10 Avatar answered Oct 21 '22 01:10

bluenote10