MiguelMunoz
MiguelMunoz

Reputation: 4972

How do I create a lambda expression from a Kotlin interface?

I have a simple Kotlin interface:

@FunctionalInterface
interface ServiceMethod<T> {
  fun doService(): T
}

This, in spite of the name, is essentially identical to Java's Supplier functional interface. The only difference is that I can implement the Supplier, and I can't implement my own.

val supplier = Supplier<String> {
  "Hello"
}
val serviceMethod = ServiceMethod<String> {
  "Hello"
}

The ServiceMethod implementation gives me a compiler error saying "Interface ServiceMethod does not have constructors." Huh? Of course it doesn't! It's a functional interface.

I know that I can write it as an anonymous inner class:

val serviceMethod = object : ServiceMethod<String> {
  override fun doService(): String {
    return "Hello"
  }
}

But this is much more verbose. In this case I could just use the Supplier interface, but that won't work for other interfaces. I shouldn't have to write an interface in Java, just to be able to a lambda in Kotlin. I'd rather use a lambda for all my Kotlin interfaces, especially since I'll be writing a lot of these. Am I missing something obvious?

Upvotes: 15

Views: 1740

Answers (1)

Sam
Sam

Reputation: 10006

Use the fun interface modifier since Kotlin 1.4

In Kotlin 1.3 and earlier, SAM (single abstract method) conversions, where you can instantiate an interface like Supplier using a lambda function, were only supported for Java interfaces.

The language designers originally thought SAM conversions wouldn't be useful for Kotlin interfaces, because a Kotlin function already has a type. For example, the type of your doService function can be written as () -> T. Instead of creating an object that implements an interface, you could simply write:

val serviceMethod: () -> String = { "Hello" }

Kotlin 1.4 adds SAM conversions for Kotlin interfaces, but it doesn't work out of the box for every interface. Instead, you have to apply the special fun modifier to a Kotlin interface to make it eligible for SAM conversion.

In your example, it would simply look like this:

fun interface ServiceMethod<T> {
  fun doService(): T
}

With the modifier added, you can create an instance using a lambda exactly as you were hoping in your question.

val serviceMethod = ServiceMethod<String> { "Hello" }

You can learn more in the Kotlin documentation for functional interfaces.

Upvotes: 23

Related Questions