Reputation: 7644
I have many classes of a common base trait. I have a function that needs to create a new instance of a instance of one of these classes, but which one is only known at runtime.
Is it possible to pass this class as a parameter and create an instance at runtime in Scala?
I'm not even sure that the answer would be the best approach but currently it's the only thing I can think of.
Upvotes: 6
Views: 1769
Reputation: 26486
The most "seamless" way to get what you want is to declare the method that will do the instantiation as having a type parameter with a context bound of ClassManifest
def maker[T : ClassManifest](args...): T = ...
which will cause the compiler to automatically pass an instance of ClassManifest[T]
to maker. The caller need only specify the particular class they want instantiated.
package rrs.scribble
import scala.reflect.ClassManifest
object Maker
{
def maker[T : ClassManifest]: T = {
val cmT = implicitly[ClassManifest[T]]
val cT = cmT.runtimeClass
cT.newInstance.asInstanceOf[T]
}
}
This only works when there is a no-arg constructor for the classes in question. You can invoke constructors with arguments, but it's a lot more involved. You'll have to familiarize yourself with the Java reflection API.
In the REPL:
scala> import rrs.scribble.Maker._
import rrs.scribble.Maker._
scala> class Argless
defined class Argless
scala> val s1 = maker[Argless]
s1: Argless = Argless@1512d075
Upvotes: 0
Reputation: 7373
I would personally avoid reflection.
If you can identify beforehand all the possible use cases and classify them using an identifier:
trait SUPER
class A extends SUPER
class B extends SUPER
class C extends SUPER
class D extends SUPER
val idA = 'CLASS_A
val idB = 'CLASS_B
val idC = 'CLASS_C
val idD = 'CLASS_D
def build(selectedId: Symbol): SUPER = selectedId match {
case 'CLASS_A => new A
case 'CLASS_B => new B
case 'CLASS_C => new C
case 'CLASS_D => new D
}
else if you prefer builders I'd follow @Edmondo1984 's advice
Upvotes: 0
Reputation: 20080
I suggest to avoid as much as you can reflection, as it can easily lead to hardly testable code and runtime exceptions.
You can, however, make a builder for that class like the following:
trait Builder[A]{
def newItem:A
}
and then pass to your func the proper builder
def myFunc[A](param1:B,builder:Builder[A])
and you can also leverage implicits
def myFunc[A](param1:B)(implicit builder:Builder[A])
Maybe you can detail a little bit more your use case?
Upvotes: 1
Reputation: 170735
Same as in Java:
classOf[MyClass].newInstance // calls the constructor without parameters
classOf[MyClass].getConstructor(/* parameter types */).newInstance(/* parameters */)
See Javadoc for Class.
This will work in any Scala version. Scala 2.10 has new reflection libraries, which are aware of Scala concepts.
Upvotes: 2
Reputation: 272267
You could pass the value thus:
myFunc(classOf[myObj])
to the method with signature
def myFunc(clazz : AnyRef)={ ...
but this smells bad. You're either looking at implementing a factory pattern, or better still you could use polymorphism and simply do:
myObj.myFunc
since your functionality is predicated on what class is involved.
Upvotes: 4