kotlingenericsextension-function

Extension function from a generic interface


Consider the following interface

interface EntityConverter<in A, out B> {
    fun A.convert(): B

    fun List<A>.convert(): List<B> = this.map { it.convert() }
}

I want to use it in a spring boot application where specific implementations get injected so that the extension function becomes usable on the type.

However this doesn't work. The compiler does not resolve the extension function.


Solution

  • Note that you're defining extension functions that are also member functions of the EntityConverter type. You should take a look at this part of the doc for information about how this works.

    Essentially, in order to use them, you need 2 instances in scope:

    You can use with() to bring the EntityConverter in scope so you can use convert on your other instances using the usual . syntax:

    val converter = object : EntityConverter<Int, String> {
        override fun Int.convert() = "#$this"
    }
    
    val list = listOf(1, 2, 3)
    
    val convertedList = with(converter) {
        list.convert()
    }
    println(convertedList) // prints [#1, #2, #3]
    

    Now you have to decide whether this kind of usage pattern is what makes most sense for your use case. If you'd prefer more "classic" calls without extensions (converter.convert(a) returning a B), you can declare your functions as regular methods taking an argument instead of a receiver.

    Bonus: functional interface

    As a side note, if you add the fun keyword in front of your EntityConverter interface, you can create instances of it very easily like this:

    val converter = EntityConverter<Int, String> { "#$this" }
    

    This is because your converter interface only has a single abstract method, making it easy to implement with a single lambda. See the docs about functional interfaces.