Java or Scala: creating new types at runtime
How do I define new types at runtime? I have a factory method that needs to create a new instance of this.type
with a marker interface. The mark开发者_如何学Goer interface was not mixed in at compile time. I need to find a way to do this at runtime.
I am using Scala, but I think the answer will be general enough to cover both Java and Scala.
trait Fruit {
def eat: this.type with Eaten = {
getClass.getConstructors()(0).newInstance(Array()).asInstanceOf[this.type];
// somehow this needs to return a new instance of this.type with the Eaten trait
// note that "Apple with Eaten" is not a type that exists at compile-time
}
}
trait Eaten // marker interface
class Apple extends Fruit
val apple1 = new Apple
val apple2 = a.eat // should return a new Apple with Eaten instance
def eater(eaten: Eaten) = ... // this function only accepts Eaten fruit
eater(apple1) // wont compile!
eater(apple2) // will compile!
This is impossible. Sure, there are ways of creating new classes at the runtime: just use any bytecode manipulation library. But this.type
is not "the class of this
", but the singleton type of this
(and there is no way to express "the class of this
" in a Scala type signature)! So
def eat: this.type with Eaten = {
// may do something here, but in the end you have to return
this
}
And of course if Apple
doesn't extend Eaten
, it won't compile, whatever you do inside the method. The usual workaround is something like
class Fruit[F : Manifest <: Fruit[F]] {
def eat: F with Eaten = {
val clazz = manifest[F].erasure
val result = // do your bytecode manipulations here
result.asInstanceOf[F with Eaten]
}
}
but this won't work if you have more than one marker interface:
val apple = new Apple // Apple
val washed = apple.wash // Apple with Washed
val eaten = washed.eat // Apple with Eaten, but no longer Washed!
I'm not exactly sure what kind of problem you are trying to solve, but maybe instead of implementing a trait you can use something like a type constructor, so Eaten becomes something like
class Eaten[T]
and Apple.eat returns an
Eaten[Apple]
JDK6 will let you compile actual Java code. See http://www.java2s.com/Code/Java/JDK-6/CompilingfromMemory.htm
Alternatively (especially if you wish to create a class to implement an interface), you should check out: java.lang.reflect.Proxy
, which will let you do something like this:
InvocationHandler handler = new MyInvocationHandler(...);
Class proxyClass = Proxy.getProxyClass(
Foo.class.getClassLoader(), new Class[] { Foo.class });
Foo f = (Foo) proxyClass.
getConstructor(new Class[] { InvocationHandler.class }).
newInstance(new Object[] { handler });
Note that JMock and the like also make this very straightforward.
Well, in Scala, there's this thing called implicit conversions that you can use. But there's no equivalent in Java though.
Your code would look something like:
implicit def fruit2eaten(fruit: Fruit) = // some way of creating an Eaten from a fruit here.
Now as far as I know (which is not much) scala is not a dynamic language, it is more of a functional language. Now in groovy - its a dynamic language, you can define a class in a string or in a text file and EVAL it at runtime, but I dont believe these things are possible in scala.
Edit : some dynamic features are coming to scala
精彩评论