Blog Infos
Author
Published
Topics
Published
Topics

Image created using photopea

 

Let’s look at a simple function with a functional type parameter in Kotlin. For simplicity, I have created this method which accepts two parameters:

  • eventName of Type String
  • completionListener of Type function which returns Unit.
fun insertEvent(eventName: String, completionListener: () -> Unit) {
    eventRepository.insert(eventName) // Consider this a delayed event
    completionListener.invoke()
}

Let’s convert this to Kotlin byte code and decompile it to the Java version.

Tools -> Kotlin -> Show Byte code -> Decompile (How To Link)

public final void insertEvent(@NotNull String eventName, @NotNull Function0 completionListener) {
   Intrinsics.checkNotNullParameter(eventName, "eventName");
   Intrinsics.checkNotNullParameter(completionListener, "completionListener");
   this.eventRepository.insert(eventName);
   completionListener.invoke();
}

Let’s break down each parameter:

  • eventName – the data type is still a String and it’s annotated with @NonNull annotation in java — this param looks straightforward.
  • completionListener — the data type looks weird its called Function0 ?? 🤔

What is Function0 if you do a control-click on Function0 it will navigate to Functions.kt

Let’s look at what Functions.kt contains:

public interface Function0<out R> : Function<R> {
    public operator fun invoke(): R
}

public interface Function1<in P1, out R> : Function<R> {
    public operator fun invoke(p1: P1): R
}

public interface Function2<in P1, in P2, out R> : Function<R> {
    public operator fun invoke(p1: P1, p2: P2): R
}
.
.
.

Function0 is nothing but an interface with invoke method that has 0 params.

Function1 is another interface with invoke method that has 1 param

Function2 is another interface with invoke method that has 2 params
and it goes on up until Function22

So under that hood, our higher-order function completionListener has been replaced by Function0 by Kotlin. If you know generics a little you should be able to picture what P1, P2, … and R are in Functions.kt

P1, P2, … are the generic types for the parameters of completionListener
R is the return generic type for the return type of the function in our case completionListener’s return type

If you still can’t picture what’s happening try calling the same function that you created in Kotlin from a Java file you can picture how it works.

Since Kotlin is designed with Java interoperability in mind, existing Java code can be called from Kotlin in a natural way, and Kotlin code can be used from Java rather smoothly as well.

//Calling the same method from Java world

public static void main(String[] args){
// Calling the same insertEvent from java world
    eventHelper.insertEvent("test", new Function0<Unit>() {
        @Override
        public Unit invoke() {
            return null;
        }
    });
}

 

Job Offers

Job Offers

There are currently no vacancies.

OUR VIDEO RECOMMENDATION

Jobs

As you can see above, we have to create an anonymous inner class for the Function0 interface to get the callback in the Java world

Ok, let’s alter completionListener and add a param:

// removed the eventName param
fun insertEvent(completionListener: (test: String) -> Unit) {
    completionListener.invoke("success")
}

This is the generated code:

public final void insertEvent(@NotNull Function1 completionListener) {
   Intrinsics.checkNotNullParameter(completionListener, "completionListener");
   completionListener.invoke("success");
}

Function0 is now replaced with Function1 to support the String param.

Hope this blog helped you understand how higher-order functions work under the hood.

Some Bonus Knowledge:
Ok, will Kotlin support any number of parameters in our higher-order functions? I got this question as I noticed something weird in Functions.kt, there are Function interfaces up to Function22. What will happen if I have more than 22 parameters? Will Kotlin throw a compile error? Let’s see…

Let’s alter our completionListener to have 23 parameters. 😅

// I have removed the string param and replaced invoke method with a println.
fun insertEvent(
    completionListener: (
        test1: String, test2: String, test3: String, test4: String, test5: String, test6: String, test7: String, test8: String, test9: String, test10: String, test11: String, test12: String, test13: String, test14: String, test15: String, test16: String, test17: String, test18: String, test19: String, test20: String, test21: String, test22: String, test23: String,
    ) -> Unit
) {
    println("Just Printing dont want to invoke it :sweat:")
}

Lets decompile …

public final void insertEvent(@NotNull FunctionN completionListener) {
   Intrinsics.checkNotNullParameter(completionListener, "completionListener");
   String var2 = "Just Printing dont want to invoke it :sweat:";
   System.out.println(var2);
}

Wow, now there is something called FunctionN. I’ll let you explore what is that.

This article was originally published on proandroiddev.com on January 01, 2023

YOU MAY BE INTERESTED IN

YOU MAY BE INTERESTED IN

blog
It’s one of the common UX across apps to provide swipe to dismiss so…
READ MORE
blog
Hi, today I come to you with a quick tip on how to update…
READ MORE
blog
Automation is a key point of Software Testing once it make possible to reproduce…
READ MORE
blog
Drag and Drop reordering in Recyclerview can be achieved with ItemTouchHelper (checkout implementation reference).…
READ MORE

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

Menu