Martin Thurau
Martin Thurau

Reputation: 7644

Pass class as value and create Instance

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

Answers (5)

Randall Schulz
Randall Schulz

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

pagoda_5b
pagoda_5b

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

Edmondo
Edmondo

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

Alexey Romanov
Alexey Romanov

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

Brian Agnew
Brian Agnew

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

Related Questions