Home > Software design >  Kotlin Return function as fun interface
Kotlin Return function as fun interface

Time:08-19

Functional interfaces work well when you want to inject a function as an interface, example:

fun interface MakeCoffee {
    operator fun invoke()
}

class CoffeeManager(private val makeCoffee: MakeCoffee) {...}

fun provideCoffeeManager(): CoffeeManager = CoffeeManager {  }

However if I try to return a function when the return type is a fun interface like this:

fun provideMakeCoffee(): MakeCoffee = {}

it will fail for a mismatch KFunction0<Unit> vs MakeCoffee.

Is there any workaround?

CodePudding user response:

fun interface enables two features. It does not make your interface fully interchangeable with matching Function type.

  1. When calling a function with that interface as a parameter, you can use any functional reference or lambda, and it will be auto-converted into that interface type. This is the only situation where functions are auto-converted into your interface, which is why the code you show doesn't work.

  2. An implicit constructor is created for your interface, where the parameter is a function matching the signature of the interface's function. This constructor creates an instance of your interface by using that function. You can use lambda syntax with this constructor to create an instance of your interface.

So in your case, you could use

fun provideMakeCoffee(): MakeCoffee = MakeCoffee {}

which calls the implicit MakeCoffee constructor, and is passing a trailing lambda parameter to it.

I’m using the word constructor loosely. It looks like a constructor call but it’s really a factory function since interfaces don’t have constructors.

CodePudding user response:

I found the solution to the problem in the end. @Tenfour04 answer works but it doesn't answer the question of "how to return a function as fun interface".

The example provided was very simple and maybe that's why the question was a bit misleading, but imagine you have the following case:

fun interface MakeCoffee {
    operator fun invoke(sugarAmount: Double, milkAmount: Double, coffeeAmount: Double)
}

//function you already have
fun doCoffee(sugarAmount: Double, milkAmount: Double, coffeeAmount: Double) { ... }

How do you return your doCoffee as MakeCoffee?

Solution

fun provideMakeCoffee(): MakeCoffee = MakeCoffee(::doCoffee)
  • Related