Benjamin Basmaci
Benjamin Basmaci

Reputation: 2567

Using type parameter from class declaration like reified type parameter in function

I want to write a function, which needs to use a the class representation of a class declaration like MyClass::class.java.

I have a base class ActivityStarter which I use as a base for companion objects in activities.

// declarations
open class ActivityCompanion<T: AppCompatActivity>(val activityClass : Class<T>) {
    fun startActivity(context: Context) {
        context.startActivity(Intent(context, activityClass))
    }
}

class MyActivity : AppCompatActivity() {
    companion object : ActivityStarter<MyActivity>(MyActivity::class:java)
...
}

// call
MyActivity.startActivity(this)

In the declaration, and the inheritence of the companion object, the class is basically passed twice. Once as type parameter and once as normal parameter. (ActivityStarter<MyActivity>(MyActivity::class:java)).

The parameter activityClass is necessary, because I cant use T::class.java. "Cannot use T as reified type parameter. Use class instead".

I have used to just pass the parameter in the function call:

// declarations
open class ActivityStarter {
    inline fun <reified T : AppCompatActivity>startActivity(context: Context) {
        context.startActivity(Intent(context, T::class.java))
    }
}

class MyActivity : AppCompatActivity() {
    companion object : ActivityStarter()
...
}

// call
MyActivity.startActivity<MyActivity>(this)

This removes the redundancy from the companion object declaration but puts it into the call and basically makes the type parameter in the class useless.

Is there a way to make the type parameter used in the class declaration reified, so that I can have an implementation like this?:

// declarations
open class ActivityCompanion<reified T: AppCompatActivity>() {
    fun startActivity(context: Context) {
        context.startActivity(Intent(context, T::class.java))
    }
}

class MyActivity : AppCompatActivity() {
    companion object : ActivityStarter<MyActivity>()
...
}

// call
MyActivity.startActivity(this)

Or another way to resctict the activityClass parameter so that I can have something like this:

// declarations
open class ActivityStarter(private val activityClass : Class<T : AppCompatActivity>) {
    inline fun startActivity(context: Context) {
        context.startActivity(Intent(context, activityClass))
    }
}

class MyActivity : AppCompatActivity() {
    companion object : ActivityStarter(MyActivity::class.java)
...
}

// call
MyActivity.startActivity(this)

Upvotes: 0

Views: 277

Answers (1)

Alexey Romanov
Alexey Romanov

Reputation: 170919

Is there a way to make the type parameter used in the class declaration reified

No. But what if you make startActivity not a member of ActivityCompanion, but an extension function so it can have reified type parameters?

class ActivityCompanion<T: AppCompatActivity>()

fun <reified T: AppCompatActivity> ActivityCompanion<T>.startActivity(context: Context) {
    context.startActivity(Intent(context, T::class.java))
}

class MyActivity : AppCompatActivity() {
    companion object : ActivityStarter<MyActivity>()
    ...
}

MyActivity.startActivity(this)

Or another way to resctict the activityClass parameter so that I can have something like this:

If I understood correctly and you want ActivityStarter to accept any subclass of AppCompatActivity without having a type parameter itself, you can write it as

open class ActivityStarter(protected val activityClass: Class<out AppCompatActivity>) { ... }

See official documentation or What is out keyword in kotlin for the meaning of out.

Upvotes: 1

Related Questions