Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement a functional interface as lambda in Kotlin?

I want to implement a functional kotlin interface (interface with a single abstract method) as a kotlin lambda. How to do that?

Kotlin interface

@FunctionalInterface
interface Foo{
  fun bar(input: String): String 
}

Kotlin implementation .

fun createFoo(): Foo {
   return { input: String -> "Hello $input!" }
}

↑ doesn't compile ↑

It has to be implemented as object, which is ugly as hell.

fun createFoo() = 
     object : Foo{
            override fun bar(input: String)= "Hello $input"
     }

EDIT: corrected my sample interface from java to kotlin

like image 287
Chriss Avatar asked Jan 25 '23 15:01

Chriss


2 Answers

Just add the fun keyword to your interface declaration:

fun interface Foo {
    fun bar(input: String): String 
}

It is the notation of functional interfaces in Kotlin (instead of @FunctionalInterface annotation in Java).

Now you can implement it like this:

Foo { input: String -> "Hello $input!" }

See more: https://kotlinlang.org/docs/fun-interfaces.html

like image 199
antaki93 Avatar answered Jan 30 '23 23:01

antaki93


since Kotlin v1.4

SAM conversion will be supported with version 1.4, with a new type inference algorithm.

See:

  • What to Expect in Kotlin 1.4 and Beyond
  • More powerful type inference algorithm

before Kotlin v1.4

It works if the companion object implements the invoke function taking a lambda.

Kotlin interface

interface Foo{
  fun bar(input: String): String

   companion object { 
      inline operator fun invoke(crossinline function: (String) -> String) =
                object : Foo{
                    override fun bar(input: String) = function(input)
                } 
   } 
}

Kotlin implementation

fun createFoo()= Foo { input: String -> "Hello $input!" }

Functional/SAM interfaces defined in kotlin can't be implemented as Kotlin lambdas by design, see KT-7770.

In Kotlin an functional / SAM interface is considered as an anti-pattern, a function type should be declared instead: (String)->String. The function type can be expressed as typealias to make it look and feel like an interface: typealias Foo=(String)->String.

Note: The typealias is not visible in Java code only in Kotlin!

like image 24
Chriss Avatar answered Jan 30 '23 22:01

Chriss