J  Calbreath
J Calbreath

Reputation: 2705

Return a class from function in Scala

I need to instantiate a different class depending on a the value of a particular argument in my application. Something like:

class x { val z = 5}
class y { val z = 10}

def myClass(input:String): Class[_] = {
  input match{
    case "x" => x
    case "y" => y
  }
 }

 val a = new myClass("x")

Any ideas how to do this or if this is possible? It tried the above code and I get a type mismatch with the output so maybe it's as simple as specifying the output type correctly, which I'm pretty sure I'm not.

Thanks.

Upvotes: 0

Views: 1839

Answers (2)

Dima
Dima

Reputation: 40500

It's not clear what it is you are actually trying to do: on one hand, you are saying that you need to instantiate the class, on the other, your function is declared to return the Class itself, not an instance.

So, if you are trying to create an instance, something like this would work:

 def myClass(input: String): AnyRef = input match {
   case "x" => new x
   case "y" => new y
 }

Note: there are two problems with this function. First, it will throw an exception if input happens to be neither x nor y ... This is not very nice. It is a better idea to make it return an Option, and add a default to None, when input isn't matched:

 def myClass(input: String): Option[_] = Option(input) collect {
    case "x" => new x
    case "y" => new y
 }

Another problem is that you cannot do very much with the value returned by this function the way it is written, because you don't know what type it has, so, you can't access any of it's members (other than the common stuff like toString, equals etc.).

It may be a better idea to define a common trait like the other answer suggests, and narrow down the return type of the function to that trait:

trait Foo { def z: Int }
class x extends Foo { val z = 5 }
class y extends Foo { val z = 10 }

def myClass(input: String): Option[Foo] = Option(input) collect {
  case "x" => new x
  case "y" => new y
}

Finally, if what you wanted was to actually return the Class object, and not an instance, then you almost have it, except, you need to add a classOf keyword (it's still better to make the result optional, in case input does not match):

 def myClass(input: String): Option[Class[_]] = Option(input) collect {
   case "x" => classOf[x]
   case "y" => classOf[y]
 }

Or, better, with the type boundary:

 def myClass(input: String): Option[Class[_ <: Foo]] = Option(input) collect {
   case "x" => classOf[x]
   case "y" => classOf[y]
 }

Upvotes: 1

darkfrog
darkfrog

Reputation: 1131

You should clarify what you're trying to accomplish because runtime reflection would allow you to do this, but 99.9% of the time it's the wrong way to solve your problems.

You can do something like:

trait A
case class B(value: String) extends A
case class C(value: Int) extends A

def doSomething(input: String): A = input match {
  case "x" => B("Wahoo")
  case "y" => C(123)
}

Upvotes: 3

Related Questions