Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin inlined extension property

I know inline keyword means to avoid the call overhead calling a funtion. But I can't figure out what inline a extension property work for?

Let say we have two extension property named foo and another with is inlined named bar

val Any.foo : Long
    get() = Date().time

inline val Any.bar : Long
    get() = Date().time

Executing any of them, we gent the expected output, the current time.

The bytecode for this file is this below:

public final class InlinedExtensionPropertyKt {

  public final static getFoo(Ljava/lang/Object;)J
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
   L0
    ALOAD 0
    LDC "$receiver"
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
   L1
    LINENUMBER 9 L1
    NEW java/util/Date
    DUP
    INVOKESPECIAL java/util/Date.<init> ()V
    INVOKEVIRTUAL java/util/Date.getTime ()J
    LRETURN
   L2
    LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
    MAXSTACK = 2
    MAXLOCALS = 1

  public final static getBar(Ljava/lang/Object;)J
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
   L0
    ALOAD 0
    LDC "$receiver"
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
   L1
    LINENUMBER 12 L1
    NEW java/util/Date
    DUP
    INVOKESPECIAL java/util/Date.<init> ()V
    INVOKEVIRTUAL java/util/Date.getTime ()J
    LRETURN
   L2
    LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
    LOCALVARIABLE $i$f$getBar I L0 L2 1
    MAXSTACK = 2
    MAXLOCALS = 2

  @Lkotlin/Metadata;(mv={1, 1, 7}, bv={1, 0, 2}, k=2, d1={"\u0000\u000e\n\u0000\n\u0002\u0010\u0009\n\u0002\u0010\u0000\n\u0002\u0008\u0005\"\u0016\u0010\u0000\u001a\u00020\u0001*\u00020\u00028\u00c6\u0002\u00a2\u0006\u0006\u001a\u0004\u0008\u0003\u0010\u0004\"\u0015\u0010\u0005\u001a\u00020\u0001*\u00020\u00028F\u00a2\u0006\u0006\u001a\u0004\u0008\u0006\u0010\u0004\u00a8\u0006\u0007"}, d2={"bar", "", "", "getBar", "(Ljava/lang/Object;)J", "foo", "getFoo", "test sources for module app"})
  // compiled from: InlinedExtensionPropertyKt.kt
}

We can see both are similar but differents only on these lines:

foo extract:

    LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
    MAXSTACK = 2
    MAXLOCALS = 1

bar extract:

    LOCALVARIABLE $receiver Ljava/lang/Object; L0 L2 0
    LOCALVARIABLE $i$f$getBar I L0 L2 1
    MAXSTACK = 2
    MAXLOCALS = 2

I really don't understand what is happennig here. Can someone point me to see what is the behaviour, or the equivalent in java, or some use for this?

Edit

Given the compiler will replace the content of inlined property, it may convenient to inline every extension property having not heavy operations ?

Thank you

like image 477
crgarridos Avatar asked Sep 21 '17 08:09

crgarridos


People also ask

What is the use of extension in Kotlin?

Extension functions are really-really helpful while writing code in Kotlin. You don't have to extend the class but you can add the functionality to even a final (non-open) class which will be resolved statically but how about extension properties.

What is inline annotation in Kotlin?

Inline annotation means that the specific function, along with the function parameters, will be expanded at the call site; this helps reduce call overhead. Similarly, the inline keyword can be used with properties and property accessors that do not have the backing field. 1. Let’s try an example where we inline an accessor of property in Kotlin:

Does it modify the existing class in Kotlin?

It does not actually modify the existing class, but it creates a callable function that can be called with a dot operation. In function extension, Kotlin allows to define a method outside of the main class. In the following example, we will see how the extension is implemented at the functional level.

How do you declare a Kotlin property?

Properties in Kotlin classes can be declared either as mutable, using the var keyword, or as read-only, using the val keyword. Copied! To use a property, simply refer to it by its name: Copied! The full syntax for declaring a property is as follows:


1 Answers

From Kotlin's doc,

Note that, since extensions do not actually insert members into classes, there's no efficient way for an extension property to have a backing field.

and also,

The inline modifier can be used on accessors of properties that don't have a backing field.

As mentioned above, an inline extension property does not have a backing field. You may treat an extension property as a pair of static getter/setter, like this:

//In Kotlin
var Any.foo : Long
    get() = Date().time
    set(value) {
        //Cannot access field here since extension property cannot have backing field
        //Do something with `obj`
    }

//In Java
public static long getFoo(Object obj) {
    return new Date().getTime();
}
public static void setFoo(Object obj) {
    //Do something with `obj`
}

So, inline property means that the code of the getter/setter function will be inlined into the call site when accessing the property (same as regular inline functions).

//In Kotlin
val x = "".foo
val y = "".bar

//Generated code
val x = InlinedExtensionPropertyKt.getFoo("")
val y = Date().time

For the bytecode that you post in the question, sorry that I am not able explain what is happening. But you may try to take a look at the bytecode of the following code:

fun get() {
    val x = "".foo
    val y = "".bar
}

, where "".foo will invoke the getter function but "".bar will not.

like image 52
BakaWaii Avatar answered Oct 21 '22 11:10

BakaWaii