Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixing in a trait dynamically

Having a trait

trait Persisted {   def id: Long } 

how do I implement a method that accepts an instance of any case class and returns its copy with the trait mixed in?

The signature of the method looks like:

def toPersisted[T](instance: T, id: Long): T with Persisted 
like image 312
Nikita Volkov Avatar asked Apr 29 '12 15:04

Nikita Volkov


1 Answers

This can be done with macros (that are officially a part of Scala since 2.10.0-M3). Here's a gist example of what you are looking for.

1) My macro generates a local class that inherits from the provided case class and Persisted, much like new T with Persisted would do. Then it caches its argument (to prevent multiple evaluations) and creates an instance of the created class.

2) How did I know what trees to generate? I have a simple app, parse.exe that prints the AST that results from parsing input code. So I just invoked parse class Person$Persisted1(first: String, last: String) extends Person(first, last) with Persisted, noted the output and reproduced it in my macro. parse.exe is a wrapper for scalac -Xprint:parser -Yshow-trees -Ystop-after:parser. There are different ways to explore ASTs, read more in "Metaprogramming in Scala 2.10".

3) Macro expansions can be sanity-checked if you provide -Ymacro-debug-lite as an argument to scalac. In that case all expansions will be printed out, and you'll be able to detect codegen errors faster.

edit. Updated the example for 2.10.0-M7

like image 97
Eugene Burmako Avatar answered Oct 07 '22 07:10

Eugene Burmako