Loading...

How do I constrain a Kotlin extension function parameter to be the same as the extended type?

Answer #1 100 %

As mentioned by @Alexander Udalov it's not possible to do directly but there's a workaround where you define the extension method on another type like so:

data class Wrapper(val value: T)

val  T.ext: Wrapper get() = Wrapper(this)

fun  Wrapper.thing(p: T) {
    println("value = $value, param = $p")
}

With the above the following compiles:

"abc".ext.thing("A")

but the next fails

"abc".ext.thing(2)

with:

Kotlin: Type inference failed: Cannot infer type parameter T in fun  Wrapper.thing(p: T): Unit
None of the following substitutions
receiver: Wrapper  arguments: (String)
receiver: Wrapper  arguments: (Int)
can be applied to
receiver: Wrapper  arguments: (Int)

As suggested by @hotkey it seems that it should be possible to avoid the need for explicit Wrapper type with the following extension property:

val  T.thing: (T) -> Any? get() = { println("extension body") }

And then use it as "abc".thing("A") but it also fails. Surprisingly the following does compile "abc".thing.invoke("A")

Answer #2 100 %

As far as I know, this is not possible in Kotlin 1.0. There are several issues in the tracker (first, second) about a similar use case, and the solution proposed in the first one is likely going to help here in the future as well.

Answer #3 100 %

Improving @miensol's workaround and making it visually identical to function call:

val  T.foo: (T) -> SomeType get() = { other -> ... }

This is an extension property that provides a lambda, which can be immediately called with an argument of the same type T like this:

"abc".foo(1) // Fail
"abc".foo("def") // OK

Unfortunately, there seems to be a bug in the compiler which prevents you from writing "abc".thing("abc"), but either of "abc".thing.invoke("abc") and ("abc".thing)("abc) work well and filter out calls with non-strings.

You’ll also like:


© 2023 CodeForDev.com -