Kotlin - Functional (SAM) interfaces VS Function types - kotlin

With Kotlin 1.4 we now have Functional Interfaces
fun interface Todo {
fun run()
}
fun runBlock(todo: Todo){
if(condition)
todo.run()
}
fun runBlock{
println("Hello world")
}
Before i was always using (T) -> T
inline fun runBlock(block: ()-> Unit){
if(condition)
block()
}
fun runBlock{
println("Hello world")
}
So basically I can make the same task with both methods , there is any performance advantage by using Functional SAM() Interfaces over Function Type?.

It's a performance dis-advantage because the lambda is no longer inlined (unless the JIT decides to, but it won't be instant). Even if you mark runBlock as inline, the compiler will warn you that the argument won't be inlined.
There are only two reasons to use fun interfaces instead of function types:
Backwards compatibility when porting code using Java functional interfaces.
Not exposing Kotlin function types in API intended for use from Java.
To expand on point 1: before Kotlin 1.4 it was advised to keep functional interfaces as Java code, even if all your other code was Kotlin. This way you could use lambdas for parameters of those types both in Java and Kotlin code. But if you declared the interface in Kotlin, you could only use lambdas for them in Java.

https://kotlinlang.org/docs/reference/whatsnew14.html#sam-conversions-for-kotlin-interfaces
the compiler automatically converts the lambda to an instance of the class that implements the abstract member function.
So, no performance advantage, it’s the same thing as before. The compiler now does what you had to do before.

As other answers and comments have pointed out, in your case, using inlined lambda is faster, since there is no function call overhead when invoking it.
However, there is one specific use case where using SAM interface is faster, that is when you 1. do not inline the lambda and 2. the arguments/return value of the lambda is a primitive (or any other type that may cause boxing when used with generics).
For example, using SAM interface like so:
fun interface Foo() {
fun run(i: Int): Int
}
fun foo(fn: Foo) {
fn.run(42)
}
foo { it * 2 }
Will not cause any boxing when invoked, while:
fun foo(fn: (Int) -> Int) {
fn(42)
}
foo { it * 2 }
Will box the integer argument since (Int) -> Int is essentially Function1<Integer, Integer> in Java, which uses generic.

Related

Kotlin Return function as fun interface

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?
fun interface enables two features. It does not make your interface fully interchangeable with matching Function type.
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.
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.
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)

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?
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.

why there is 'by' for the extended class and reified in function define

coming across a sample with a class and a function and trying to understand the koltin syntax there,
what does this IMeta by dataItem do? looked at https://kotlinlang.org/docs/reference/classes.html#classes and dont see how to use by in the derived class
why the reified is required in the inline fun <reified T> getDataItem()? If someone could give a sample to explain the reified?
class DerivedStreamItem(private val dataItem: IMeta, private val dataType: String?) :
IMeta by dataItem {
override fun getType(): String = dataType ?: dataItem.getType()
fun getData(): DerivedData? = getDataItem()
private inline fun <reified T> getDataItem(): T? = if (dataItem is T) dataItem else null
}
for the reference, copied the related defines here:
interface IMeta {
fun getType() : String
fun getUUIDId() : String
fun getDataId(): String?
}
class DerivedData : IMeta {
override fun getType(): String {
return "" // stub
}
override fun getUUIDId(): String {
return "" // stub
}
override fun getDataId(): String? {
return "" // stub
}
}
why the reified is required in the inline fun <reified T> getDataItem()? If someone could give a sample to explain the reified?
There is some good documentation on reified type parameters, but I'll try to boil it down a bit.
The reified keyword in Kotlin is used to get around the fact that the JVM uses type erasure for generic. That means at runtime whenever you refer to a generic type, the JVM has no idea what the actual type is. It is a compile-time thing only. So that T in your example... the JVM has no idea what it means (without reification, which I'll explain).
You'll notice in your example that you are also using the inline keyword. That tells Kotlin that rather than call a function when you reference it, to just insert the body of the function inline. This can be more efficient in certain situations. So, if Kotlin is already going to be copying the body of our function at compile time, why not just copy the class that T represents as well? This is where reified is used. This tells Kotlin to refer to the actual concrete type of T, and only works with inline functions.
If you were to remove the reified keyword from your example, you would get an error: "Cannot check for instance of erased type: T". By reifying this, Kotlin knows what actual type T is, letting us do this comparison (and the resulting smart cast) safely.
(Since you are asking two questions, I'm going to answer them separately)
The by keyword in Kolin is used for delegation. There are two kinds of delegation:
1) Implementation by Delegation (sometimes called Class Delegation)
This allows you to implement an interface and delegate calls to that interface to a concrete object. This is helpful if you want to extend an interface but not implement every single part of it. For example, we can extend List by delegating to it, and allowing our caller to give us an implementation of List
class ExtendedList(someList: List) : List by someList {
// Override anything from List that you need
// All other calls that would resolve to the List interface are
// delegated to someList
}
2) Property Delegation
This allows you to do similar work, but with properties. My favorite example is lazy, which lets you lazily define a property. Nothing is created until you reference the property, and the result is cached for quicker access in the future.
From the Kotlin documentation:
val lazyValue: String by lazy {
println("computed!")
"Hello"
}

Why can't make to methods with same name but with different generics?

I'm pretty new in Kotlin language, but I have just encountered some strange behavior that didn't have in other languages, so I wanted to ask why I can't do something like this:
fun <T> methodName()
{
// whatev~
}
fun <T, K> methodName()
{
// whatev~
}
This code throws an error of "Conflicting overloads".
In other languages, for example C# I can do this and it's a pretty neat trick to have only one method that work for one or multiple types at the same time.
The only workaround I've found it's adding in each new method that I do an optional parameter that I'll never use, like:
fun <T> methodName()
{
}
fun <T, K> methodName(crappyParam: String = "")
{
}
The two methods would have the same signature in JVM type system (which doesn't support generics), which isn't allowed.
A JVM language could "mangle" such methods, e.g. giving them different names in bytecode. A JVM implementation of C# would have to.
But Kotlin doesn't. And doing so would hurt interoperability with Java, which is one of Kotlin's major requirements.

Possible to keep `Unit` as the return type of a Kotlin function when called from Java?

I have a kotlin function inside a sealed class.
fun invoke(callback: Callback): Unit
Java sees the method signature as a function that returns void.
Is it possible to instruct the Kotlin compiler to keep Unit as the return type for Java? (not void)
Use case
My use case is a jvm interop issue from Java where I need to implement (Result) -> Unit.
// inside a java method (currently)
abstractClass.invoke(callback)
return Unit.INSTANCE
// what I'd prefer instead
return abstractClass.invoke(callback) // invoke returns Unit, but it's in Kotlin, so it maps to void in Java. So this doesn't work
For your edge case, you'd still have to deal with Java methods returning void. So just solve it once:
fun <T> fromConsumer(consumer: Consumer<T>): (T) -> Unit = { consumer.consume(it) }
and then instead of implementing (Result) -> Unit directly, implement/create a Consumer<Result> and pass it to this function. It could be written in Java as well, just would be more complicated.
It would certainly be possible to do this in Java:
public kotlin.Unit test() { return null; }
But in Kotlin your best option seems to be to go with a function object:
val invoke: (Callback) -> Unit = {}
// from Java:
return abstractClass.getInvoke(callback)
I may have misunderstood your question.
First, in Kotlin,
fun invoke(callback: Callback): Unit
is equivalent to
fun invoke(callback: Callback)
In Java, if you override a function like that, you do not need to return anything.
Is it possible to instruct the Kotlin compiler to keep Unit as the return type for Java? (not void)
No, because Unit is meaningless. The only valid value of Unit is Unit itself.