0

I have the following:

trait C {}

object O {
    case class Foo(bar: String) extends C
}

And I would like to instance Foo from a String. Until the moment I have achieved instanciate Foo, but I cannot cast to C. I am using:

val ob = runtimeMirror.staticModule("O.Foo")
val foo = runtimeMirror.reflectModule(ob).instance

Now foo is an instance of O.Foo, but it cannot be cast to C.

val c = foo.asInstanceOf[C] 

This very last line returns:

O$foo$ cannot be cast to C
ie8888
  • 171
  • 1
  • 10
  • Using reflection is rarely a good solution, and using `asInstanceOf` even less. Rather use a factory pattern (e.g. https://stackoverflow.com/a/45654971/3347384 ) – cchantep Aug 13 '17 at 12:25
  • 1
    I think `C` is a supertrait of the _instances_ of `Foo`, not the companion object of `O.Foo` you are referring to. – Gábor Bakos Aug 13 '17 at 14:36
  • @cchantep thanks but it doesn't work for me. @GáborBakos please see again my code, I want to instantiate the case class `Foo` which has as supertrait `C`, I don't have any companion object for `Foo` – ie8888 Aug 14 '17 at 07:52
  • @ie8888 nothing prevent you from adding a companion, which is a quite common/good practice in Scala (contrary to using reflection which is a quite bad practice, even in vanilla Java) – cchantep Aug 14 '17 at 08:43
  • @ie8888, your question's code doesn't do what you think it does. It gets the *object* `O.Foo`, which is the companion object of the *class* `O.Foo`. You are not creating a new instance, you are simply getting the already existing companion. If you actually made an `O.Foo`, then the cast to `C` would succeed, but you only get an `O.Foo.type`, which is not a `C`. – HTNW Aug 14 '17 at 18:28
  • You are totally right @HTNW. Now I see why it doesn't work.Thanks – ie8888 Aug 15 '17 at 15:49

2 Answers2

0

The solution was much easier than I have ever thought.

Class.forName("O$Foo").newInstance

It should be noted that with this solution requires that Foo has a constructor without args. This last condition is not a problem for my code, so it is solved.

ie8888
  • 171
  • 1
  • 10
-1

Case classes extending a trait will implement only in their class, not in their companion object for example see:

trait C {}

object O {
  case class Foo(bar: String) extends C
  case class Foo2(bar: String) extends C
  object Foo2 extends C
}

object Q extends App {
  import scala.reflect.runtime.universe._
  val rm = runtimeMirror(getClass.getClassLoader)

  for (ref <- Seq("O.Foo", "O.Foo2")) {
    val ob = rm.staticModule(ref)
    val foo = rm.reflectModule(ob).instance
    println(foo.isInstanceOf[C])
  }
}

This prints:

false

true

When you are referring to the staticModules, you are referring to the companion objects, that is why C is not implemented by the class you were testing.

Community
  • 1
  • 1
Gábor Bakos
  • 8,982
  • 52
  • 35
  • 52