Reified type parameters through inline constructors

#1

Hello everyone.

There are situations where it is useful having a class with a generic type parameter that holds some kind of information or has some kind of behaviour related to the generic parameter, like being able to produce the class name or create a new instance of the generic type.
Because, currently, kotlin does not support reified type parameters for classes, a common solution for this problem is to pass a class object with the same type as the generic type to the constructor. To illustrate this idea, consider the following class. Bear in mind that this is a toy example and it is simple so that it is easy to understand.

open class A<T>(private val type: Class<T>) {

    val name: String
        get() = type.name

    fun newInstance(): T = type.newInstance()
}

If we need to subclass the previous class we would do something like the following:

class StringA : A<String>(String::class.java) {

    fun aMethod() {
        // code
    }
}

Notice that we have to reference the String class twice: once as type parameter and again to get its corresponding java Class instance, even though, we know that the only Class instance that is reasonable to be passed to the constructor has to be the String Class instance.

It would be nice if we instead simply subclass A like this:

class StringA : A<String>() {

    fun aMethod() {
        // code
    }
}

To allow this, i suggest the implementation of inline constructors in kotlin that would allow reified type parameters to be passed to the constructor.
Going back to class A, if it had inline constructors, it could be something like this:

open class A<T>(private val type: Class<T>) {

  inline constructor<reified T>() : this(T::class.java)

  val name: String
      get() = type.name

  fun newInstance(): T = type.newInstance()
}

class StringA : A<String>() // subclassing using inline constructor

It is important to notice, that for this to work, the inline constructor must reference a “concrete” constructor for which it will be inlined.
Also, “reified T” in the constructor should be a type parameter of the constructor, however, and considering that, currently, kotlin does not support type parameters on constructors, this could reference the class generic type parameter.

What do people think about this?

1 Like
#2

I solved situation like this with a create / build function on the companion object instead of logic in constructor. I’m not sure if this is a “good” approach in general, to weaken some “constraints” in object creation.

1 Like
#3

Let’s say it this way. Such a constructor could not normally be used by an inheriting class. An inline factory function seems appropriate here although one needs to be written for each subclass.

#4

@pdvrieze, @werrenmi
If all we need is to create instances of a particular class, then yes, an inline create / build function / method is more than enough, but the idea here is to enable reified type parameter in places where only a constructor is allowed and you couldn’t use a function / method, like in my StringA subclass example.

PS: I fixed the code formatting. Before you couldn’t see the <String> in some places. Now you can. I hope that clarifies my idea.

#5

I see your point. However I’m not sure about it. In most cases subclassing fairly infrequent (where creating new instances is not). This is one of those features that struggle with the -100 points rule. As in every feature added to the language creates a cost to the language (evolution) and its use. The feature is worthwhile, but there are simple alternatives that are not unduly burdensome.

As an example of possible issues/cost, how would it interact with pattern matching? A feature that is certainly under consideration (even in Java). To push the feature you should probably identify use cases where the feature has clear benefits.