ademar111190
ademar111190

Reputation: 14515

Set a default value for kotlin generics

I have this extension function:

fun <T : View> Activity.bind(idRes: Int): Lazy<T> = lazy { findViewById<T>(idRes) }

as you can see my generic T should be View or a descendant.

whenever I want to use it to get a View descendant I do one of the following options:

val textView1 by bind<TextView>(R.id.text_view_1)
val textView2: TextView by bind(R.id.text_view_2)

pretty nice, but lets us see the problem now, sometimes I don't need the specific type, I just need View, for example when I want to set a click listener, so I have to do this:

val view1 by bind<View>(R.id.view_1)
val view2: View by bind(R.id.view_2)

I'm wondering a way to remove the explicitly type View, to make the kotlin compiler see it is the default once I defined T : View, is it possible?

In other words I want this:

val textView1 by bind<TextView>(R.id.text_view_1)
val textView2: TextView by bind(R.id.text_view_2)
val view by bind(R.id.view_xyz) // kotlin compiler understands it is a View

I did try it:

fun Activity.bind(idRes: Int): Lazy<View> = lazy { findViewById<View>(idRes) }

fun <T : View> Activity.bind(idRes: Int): Lazy<T> = lazy { findViewById<T>(idRes) }

but I got:

Platform declaration clash: The following declarations have the same JVM signature

What does make sense because of the generic type erasure…

I'm wondering for a solution that doesn't involve another method like fun Activity.bindView... because I want to keep the API as simple as possible.

P.S. The synthetic option has several bugs and it is the reason we are using this lazy bind is to move away from it.

Upvotes: 6

Views: 2414

Answers (1)

ardenit
ardenit

Reputation: 3890

Kotlin compiler will always infer the most specific generic type, and there is no such thing as "default" type parameter, so you have to create extra function. You may use JvmName annotation to resolve the platform declaration crash:

fun <T> foo(): T? = null

@JvmName("foo0")
fun foo(): Any? = null

fun main() {
    foo<Nothing>()
    foo()
}

Upvotes: 6

Related Questions