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
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 forscalac -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
While it's not possible to compose an object AFTER it's creation, you can have very wide tests to determine if the object is of a specific composition using type aliases and definition structs:
Any object with a
def id:Long
will qualify as Persisted.Achieving what I THINK you are trying to do is possible with implicit conversions:
What you are trying to do is known as record concatenation, something that Scala's type system does not support. (Fwiw, there exist type systems - such as this and this - that provide this feature.)
I think type classes might fit your use case, but I cannot tell for sure as the question doesn't provide sufficient information on what problem you are trying to solve.
Update
You can find an up to date working solution, which utilizes a Toolboxes API of Scala 2.10.0-RC1 as part of SORM project.
The following solution is based on the Scala 2.10.0-M3 reflection API and Scala Interpreter. It dynamically creates and caches classes inheriting from the original case classes with the trait mixed in. Thanks to caching at maximum this solution should dynamically create only one class for each original case class and reuse it later.
Since the new reflection API isn't that much disclosed nor is it stable and there are no tutorials on it yet this solution may involve some stupid repitative actions and quirks.
The following code was tested with Scala 2.10.0-M3.
1. Persisted.scala
The trait to be mixed in. Please note that I've changed it a bit due to updates in my program
2. PersistedEnabler.scala
The actual worker object
3. Sandbox.scala
The test app
It is not possible to achieve what you want using vanilla scala. The problem is that the mixins like the following:
create a
Foo with Bar
mixed in, but it is not done at runtime. The compiler simply generates a new anonymous class:See Dynamic mixin in Scala - is it possible? for more info.