Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin - Higher Order Functions Costs?

Is there any cost of Higher Order Functions? I can solve some problems with it easily but I am not sure can it effect performance. Are there any limitations about it?

like image 467
rooest Avatar asked Jan 07 '18 19:01

rooest


People also ask

Does Kotlin support higher order functions?

Kotlin functions are first-class, which means they can be stored in variables and data structures, and can be passed as arguments to and returned from other higher-order functions.

Why do we need higher order functions in Kotlin?

In Kotlin, a function which can accept a function as parameter or can return a function is called Higher-Order function. Instead of Integer, String or Array as a parameter to function, we will pass anonymous function or lambdas. Frequently, lambdas are passed as parameter in Kotlin functions for the convenience.

What is () -> unit in Kotlin?

Unit in Kotlin corresponds to the void in Java. Like void, Unit is the return type of any function that does not return any meaningful value, and it is optional to mention the Unit as the return type. But unlike void, Unit is a real class (Singleton) with only one instance.


1 Answers

Lambdas passed to higher-order functions are compiled to generic Function objects. This approach certainly adds some costs, also due to boxing overhead when primitive types are involved.
So yes, it can effect performance. You should use inline higher order functions whenever it makes sense because the aforementioned caveats won’t be problematic anymore.

Taken from the docs:

Using higher-order functions imposes certain runtime penalties: each function is an object, and it captures a closure, i.e. those variables that are accessed in the body of the function. Memory allocations (both for function objects and classes) and virtual calls introduce runtime overhead.

But it appears that in many cases this kind of overhead can be eliminated by inlining the lambda expressions.

There are certain restrictions for inline though. Read in the docs.

Example

Definition of higher-order function and caller code:

fun hoFun(func: (Int) -> Boolean) {
    func(1337)
}

//invoke with lambda
val mod = 2
hoFun { it % mod == 0 }

Bytecode Java Representation:

public static final void hoFun(@NotNull Function1 func) {
  Intrinsics.checkParameterIsNotNull(func, "func");
  func.invoke(1337);
}

final int mod = 2;
hoFun((Function1)(new Function1() {

     public Object invoke(Object var1) {
        return this.invoke(((Number)var1).intValue());
     }

     public final boolean invoke(int it) {
        return it % mod == 0;
     }
}));

As mentioned, the lambda is compiled to a Function object. Each invocation leads to the instantiation of a new Functionobject because the mod needs to be captured. Non-capturing lambdas use singleton Function instances instead.

With inline modifier applied to the higher-order function the compiled call looks much better:

int mod = 2;
int it = 1337;
if (it % mod == 0) {
   ;
}
like image 62
s1m0nw1 Avatar answered Oct 02 '22 01:10

s1m0nw1