Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define functional interface with generics in Kotlin?

Tags:

kotlin

I'm learning Kotlin and I have some trouble with functions. I'm trying to create something like a functional interface with a generic parameter. In Java I would create something like this:

@FunctionalInterface
public interface Foo<T extends Bar> {
    String something(T arg);
}

Then I can use this somewhere else like this (given that Person extends Bar:


Foo<Person> f = p -> p.toString();

How do you write this with Kotlin?

The first thing I tried was to use type-aliases like this:

typealias Foo<T> = (T) -> String

However, it stopped working when I added the bound to the type parameter:

typealias Foo<T: Bar> = (T) -> String  // Error: Bounds are not allowed on type alias parameters

The second approach was to write an interface that extends the function type:

interface Foo<T: Bar> : (T) -> String

However, now I don't know how to instantiate a lambda function from with this. It works when I create class from it like this:

class Something: Foo<Person> {
    override fun invoke(p: Person): String {
        return p.toString()
    }
}

val f = Something()

But this is a big overhead and I'm sure there has to be a better solution.

So how can I define a function signature that can be reused by many functions that supports generic parameters with bounds in kotlin?

like image 234
Manuel Mauky Avatar asked Mar 25 '19 19:03

Manuel Mauky


People also ask

CAN interface have generics?

Generic interfaces can inherit from non-generic interfaces if the generic interface is covariant, which means it only uses its type parameter as a return value.

What is generic functional interface?

A lambda expression can't specify type parameters, so it's not generic. However, a functional interface associated with lambda expression is generic. In this case, the target type of lambda expression has determined by the type of argument(s) specified when a functional interface reference is declared.

How do you get the generic parameter class in Kotlin?

There are no direct ways to do this in Kotlin. In order to check the generic type, we need to create an instance of the generic class<T> and then we can compare the same with our class.


1 Answers

Most of the time (always?) it is sufficient to define the type of the lambda in the parameter of the function that receives it.

For example:

open class Bar
class Person: Bar()

var f = { p: Person -> p.toString() }

fun <T : Bar> withFoo(block: (T) -> String) { }
fun <T : Bar> otherFoo(block: (T) -> String) { }   

fun main() {
    withFoo(f)
    otherFoo(f)
}

The same way the Kotlin documentation states: "since Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported."

See https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions

like image 177
Alexander Egger Avatar answered Oct 23 '22 05:10

Alexander Egger