2

In Scala, even if the solution is not elegant, is it possible to instantiate/create a new object of a generic type T? Is it possible to achieve this using reflection?

For example, I am interested in something like the following:

    case class Person(name: String, age: Int)

Let's say I wanted to do the following to create an object of type Person:

    def createObject[T](fieldValues: Seq[Any]): T = {
        ... T(fieldValues)
    }

    val person = createObject[Person](Seq("Bob", 20))
Krzysztof Atłasik
  • 21,985
  • 6
  • 54
  • 76
code
  • 5,294
  • 16
  • 62
  • 113
  • 1
    Where are coming from the `Seq[Any]`? Would suggest to think about a typeclass rather than unsafe runtime reflection. – cchantep Aug 07 '20 at 09:55
  • duplication of https://stackoverflow.com/questions/21715164/how-to-create-an-instance-of-type-t-at-runtime-with-typetags – Artem Sokolov Aug 07 '20 at 11:03
  • 1
    Does this answer your question? [How to create an instance of type T at runtime with TypeTags](https://stackoverflow.com/questions/21715164/how-to-create-an-instance-of-type-t-at-runtime-with-typetags) – Artem Sokolov Aug 07 '20 at 11:03
  • If `T` is a case class you can do this even at compile time (using compile-time reflection i.e. macros under the hood) https://scastie.scala-lang.org/R7JABtX1RjizE7BsaPVqeQ – Dmytro Mitin Aug 07 '20 at 14:10

2 Answers2

9

No, it is not possible. T is a parameter. You do not know anything about it. You do not even know if it can be instantiated at all. It might be a trait or an abstract class or a singleton type or a compound type.

That is the whole point of parametric polymorphism. To write code that does not need to know anything about the types it is dealing with.

Just as an example, it is perfectly legal to call your method like this:

val goodLuck = createObject[Nothing](Seq(1, 2))

Well, Nothing is literally defined as "the type which cannot have an instance". How are you going to instantiate this?

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • 1
    I see, Thanks Jorg. Just curious, If T extends from a class that I know has a constructor, is it syntactically possible to instantiate the generic type T? – code Aug 07 '20 at 10:50
  • 1
    You can use implicit evidence to provide some factory - if type has implicit you can use it to create an instance. But passing sequence of `Any` is really a bad design, where at best you could return `Option[T]` to indicate that arguments might not match what class expected. – Mateusz Kubuszok Aug 07 '20 at 11:59
3

Technically speaking it's possible using reflection. You could for example catch runtime class of type T using ClassTag then find proper constructor and create instance:

def createObject[T](fieldValues: Seq[Any])(implicit ct: ClassTag[T]): Option[T] = {
   //we lookup for matching constructor using arguments count, you might also consider checking types
   ct.runtimeClass.getConstructors.find(_.getParameterCount == fieldValues.size) 
   .flatMap {constructor =>
        Try(constructor.newInstance(fieldValues: _*).asInstanceOf[T]).toOption
    }
}

createObject[Person](Seq("Bob", 20)) //Some(Person("Bob", 20))
createObject[Person](Seq(20, 10)) //None

In case there's no constructor matching parameters, that function fails returning None.

It should work, but it'd be best if you can avoid this approach because you lose all type safety.

Krzysztof Atłasik
  • 21,985
  • 6
  • 54
  • 76
  • Thanks @Krzysztof. This was what I was looking for. It looks fine to me but seems to throw error: "type mismatch" found: Seq[Any] , required: Seq[Object] – code Aug 08 '20 at 06:42
  • 1
    Oh I see, it is because the input is of type Any and the constructor is from Java expecting type Object. – code Aug 08 '20 at 06:56