Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to instantiate a new instance of generic type

Tags:

kotlin

In C# you can place a new constraint on a generic to create a new instance of the generic parameter type, is there an equivalent in Kotlin?

Right now my work around is this:

fun <T> someMethod(class : () -> T) {
    val newInstance = class()
}

and I'm calling someMethod() like this

someMethod<MyClass>(::MyClass)

but I would like to do something like this:

fun <T : new> someMethod() {
    val newInstance = T()
}

Is that possible?

like image 661
Jaja Harris Avatar asked Oct 21 '15 22:10

Jaja Harris


Video Answer


2 Answers

Currently, that's not possible. You can give a thumbs-up for the issue https://youtrack.jetbrains.com/issue/KT-6728 to vote for the addition of this feature.

At least, you can leave out the generic type because Kotlin can infer it:

someMethod(::MyClass)
like image 61
Kirill Rakhman Avatar answered Oct 14 '22 23:10

Kirill Rakhman


A solution:

1/ use an inline function with preserved param type (reified type)

2/ in this inline function, invoque the needed constructor using class introspection (reflexion *) /!\ an inline function can't be nested/embedded in a class or function

Let see how it works on a simple example:

// Here's 2 classes that take one init with one parameter named "param" of type String
//!\ to not put in a class or function

class A(val param: String) {}
class B(val param: String) {}

// Here's the inline function.
// It returns an optional because it could be passed some types that do not own
// a constructor with a param named param of type String

inline fun <reified T> createAnInstance(value: String) : T? {

    val paramType = String::class.createType() //<< get createAnInstance param 'value' type

    val constructor = T::class.constructors.filter {
        it.parameters.size == 1 && it.parameters.filter { //< filter constructors with 1 param
            it.name == "param" && it.type == paramType //< filter constructors whose name is "param" && type is 'value' type
        }.size != 0
    }.firstOrNull() //< get first item or returned list or null

    return constructor?.call(value) // instantiate the class with value

}

// Execute. Note that to path the type to the function val/var must be type specified. 

val a: A? = createAnInstance("Wow! A new instance of A")

val b: B? = createAnInstance("Wow! A new instance of B")

*) kotlin-reflect.jar must be included in the project

In Android Studio: add to build.gradle(Module: app): implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"

like image 21
Luc-Olivier Avatar answered Oct 14 '22 22:10

Luc-Olivier