named functions vs lambda reflexion - kotlin

I am still learning Kotlin and trying to understand its core principles. What I do not get is this:
fun x() : Int { return 10 }
val y : () -> Int = ::x
val z : () -> Int = { 10 }
fun main(args: Array<String>) {
println(::x)
println(y)
println(z)
}
we get the following output:
fun x(): kotlin.Int
fun x(): kotlin.Int
() -> kotlin.Int
My question is why the output is not the same (I believed these functions should be interchangeable, equivalent)? I think the type of all the functions should be () -> Int. Why do we keep the original name with the function signature (fun x) even though it is assigned to a different name (y)? Is there any language design principle which would require such difference in function signatures?
And a bonus question - why do we need to use the operator ::. It does not compile without it. But why is this required by the language design? Would not val y = x work just fine and be much simpler?

fun x() is an ordinary named function from procedural programming. val y is a property which holds a reference to x. val z is an anonymous functional from functional programming.
:: is a 'function reference', a kind of bridge between procedural and functional programming.
By default, your functions should be fun. Lambda expressions (anonymous functions), on the other side, are intended to be passed to other functions as callbacks.

IF you think from my point of view, I think you can understand it immediately.
x just is an identifier not a variable, so you can't reference it directly.
fun x() is a class which derived from Function0.
the expression ::x is the instance of the type of fun x(), this is called function reference expression in kotlin.
Kotlin makes functions and properties first-class citizens in the language, and introspecting them.
sometimes function has it own class in kotlin like as java-8 lambda expression. but function reference expression can't used with the diff receiver.
when calling an inline function followed with a lambda, both the lambda & the function will be inlined at call-sites. but call with a non-inline function reference expression, only the inline function will be inlined at call-sites.

I think for better understanding look at bytecode
private final static Lkotlin/jvm/functions/Function0; y
#Lorg/jetbrains/annotations/NotNull;() // invisible
// access flags 0x1A
// signature Lkotlin/jvm/functions/Function0<Ljava/lang/Integer;>;
// declaration: kotlin.jvm.functions.Function0<java.lang.Integer>
private final static Lkotlin/jvm/functions/Function0; z
#Lorg/jetbrains/annotations/NotNull;() // invisible
// access flags 0x19
public final static main([Ljava/lang/String;)V
#Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
L0
ALOAD 0
LDC "args"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
L1
LINENUMBER 6 L1
GETSTATIC MainKt$main$1.INSTANCE : LMainKt$main$1;
ASTORE 1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 1
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L2
LINENUMBER 7 L2
GETSTATIC MainKt.y : Lkotlin/jvm/functions/Function0;
ASTORE 1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 1
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L3
LINENUMBER 8 L3
GETSTATIC MainKt.z : Lkotlin/jvm/functions/Function0;
ASTORE 1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 1
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
L4
LINENUMBER 9 L4
RETURN
L5
LOCALVARIABLE args [Ljava/lang/String; L0 L5 0
MAXSTACK = 2
MAXLOCALS = 2
// access flags 0x19
public final static x()I
L0
LINENUMBER 11 L0
BIPUSH 10
IRETURN
MAXSTACK = 1
MAXLOCALS = 0
// access flags 0x19
// signature ()Lkotlin/jvm/functions/Function0<Ljava/lang/Integer;>;
// declaration: kotlin.jvm.functions.Function0<java.lang.Integer> getY()
public final static getY()Lkotlin/jvm/functions/Function0;
#Lorg/jetbrains/annotations/NotNull;() // invisible
L0
LINENUMBER 12 L0
GETSTATIC MainKt.y : Lkotlin/jvm/functions/Function0;
ARETURN
MAXSTACK = 1
MAXLOCALS = 0
// access flags 0x19
// signature ()Lkotlin/jvm/functions/Function0<Ljava/lang/Integer;>;
// declaration: kotlin.jvm.functions.Function0<java.lang.Integer> getZ()
public final static getZ()Lkotlin/jvm/functions/Function0;
#Lorg/jetbrains/annotations/NotNull;() // invisible
L0
LINENUMBER 13 L0
GETSTATIC MainKt.z : Lkotlin/jvm/functions/Function0;
ARETURN
MAXSTACK = 1
MAXLOCALS = 0
// access flags 0x8
static <clinit>()V
L0
LINENUMBER 12 L0
GETSTATIC MainKt$y$1.INSTANCE : LMainKt$y$1;
CHECKCAST kotlin/jvm/functions/Function0
PUTSTATIC MainKt.y : Lkotlin/jvm/functions/Function0;
L1
LINENUMBER 13 L1
GETSTATIC MainKt$z$1.INSTANCE : LMainKt$z$1;
CHECKCAST kotlin/jvm/functions/Function0
PUTSTATIC MainKt.z : Lkotlin/jvm/functions/Function0;
RETURN
MAXSTACK = 1
MAXLOCALS = 0
}
y and z value have type Function0
static <clinit>()V // here we have static initialization block where y and z are initialized
x have type MainKt$main$1
In each case(println) we just show method declaration(visibility modifiers, return type, signature) without invocation.
y and z are high order function that in bytecode are presented by Function0 class, for x value it's just static function.
And when you invoke println(::x) println(y) println(z) you just print functions declarations. This is ok, that declaration of x and y functions are different that in z function. Because y has reference to x function and z are still high order function that return 10. In simple words y == x, because you assign to y function declaration from x.
Just for Note. In Java I can show method declaration in this way:
public static void main(String[] args) {
try {
System.out.println(Main.class.getMethod("A", null)); // prints public static void Main.A()
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public static void A() {
System.out.println(15);
}
Conclusion:
In your code you just print function return type, visibility modifier and signature.

Related

!= null VS ?.let { } performance for immutable variables in kotlin

From what I understand, the big advantage of ?.let{} over != null is it guarantees that a mutable value is not changed inside the block.
However, in case of an immutable variable is there a performance difference?
For example, I have a simple method
private fun test() {
val x: String? = ""
if (x != null) {
print("test")
}
x?.let {
print("test")
}
}
When I see the resulting Kotlin Bytecode it seems that for let it has much more code.
For the x != null case:
LINENUMBER 8 L1
L2
LINENUMBER 9 L2
LDC "test"
ASTORE 2
L3
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 2
INVOKEVIRTUAL java/io/PrintStream.print (Ljava/lang/Object;)V
L4
L5
For x?.let { } case it is:
LINENUMBER 12 L5
ALOAD 1
ASTORE 2
L6
L7
ALOAD 2
ASTORE 3
L8
ICONST_0
ISTORE 4
L9
LINENUMBER 13 L9
LDC "test"
ASTORE 5
L10
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 5
INVOKEVIRTUAL java/io/PrintStream.print (Ljava/lang/Object;)V
L11
L12
LINENUMBER 14 L12
L13
NOP
L14
LINENUMBER 12 L14
L15
NOP
L16
If I decompile to java then the resulting code seems similar with one more variable being assigned for let (curiously an int variable is set to false)
For x != null:
String var2 = "test";
System.out.print(var2);
For x?.let { }
int var4 = false;
String var5 = "test";
System.out.print(var5);
In the end, my question is: Is there a performance different between let and != for immutable variables?
The two statements are not really equivalent. The outcome is obviously the same in your two examples, but let is a scope function and thus is doing a bit more lifting than simple flow control.
From the linked documentation:
The Kotlin standard library contains several functions whose sole purpose is to execute a block of code within the context of an object. When you call such a function on an object with a lambda expression provided, it forms a temporary scope.
For example even if you're not using the it in your example, this context with the it-variable is still created and that bears some overhead with it.
However, as others have pointed out I think this is a case where it's better to optimize the code for readability over speed in this case. In cases where a let allows for more readable code (which IMO is usually the case), that's a bigger win than the miniscule performance gain you may get from using an if instead.

Evaluate code block in Kotlin (to hide variables inside scope)

In Scala, you can write
val x = {
... do some complex computations ..
42
}
to hide stuff inside of the code block.
The closest I came in Kotlin is:
val x = {
... do some complex computations ..
42
}()
Is there a better way?
EDIT:
isn’t run {} in the above example essentially the same
is calling run costly?
ANSWER:
using run {} inlines, whereas {}() does NOT (see my own answer below)
Use the run function. It takes a function as a parameter, runs it and returns the result.
val x = run {
... do some complex computations ..
42
}
The run function is inlined, so it will have no performance overhead.
Yes there is the run function.
val x = run {
...
42
}
And also you can use these methods too:
val a=1.also{
// your code
}
val b=2.apply{
// your code}
}
val c=3.let{
// your code
}
val d=4.runCatching{
// your code
}
To verify inlining when using run, I created a small example:
fun main() {
{
Math.random()
}()
run {
Math.random()
}
}
and viewed the produced bytecode:
public final static main()V
L0
LINENUMBER 2 L0
GETSTATIC TestKt$main$1.INSTANCE : LTestKt$main$1;
CHECKCAST kotlin/jvm/functions/Function0
INVOKEINTERFACE kotlin/jvm/functions/Function0.invoke ()Ljava/lang/Object; (itf)
POP
L1
LINENUMBER 6 L1
L2
L3
L4
ICONST_0
ISTORE 0
L5
LINENUMBER 7 L5
INVOKESTATIC java/lang/Math.random ()D
L6
L7
LINENUMBER 6 L7
L8
POP2
L9
LINENUMBER 9 L9
RETURN
L10
LOCALVARIABLE $i$a$-run-TestKt$main$2 I L5 L7 0
MAXSTACK = 2
MAXLOCALS = 1
So, indeed:
Calling via () calls a generated Function0-derived class that encapsulates the block as a lambda (label L0)
Calling via run fully inlines the block (label L5)

Extension function and tail call optimization (TCO) in Kotlin

I have the following function that uses TCO:
tailrec fun superDigit(n: String): Int {
val sum = n.fold(0) { sum, char -> sum + char.toString().toInt() }
return if (sum < 10) sum else superDigit(sum.toString())
}
If I implement the same function as an extension function like this:
fun String.superDigit(): Int {
val sum = fold(0) { sum, char -> sum + char.toString().toInt() }
return if (sum < 10) sum else sum.toString().superDigit()
}
Is the extension function tail call optimized as well?
IMO calling the extension function is still a regular function call with this as parameter so it's still a recursive call and since tailrec can't be used in extension functions, my assumption is that it's not been optimized by the compiler. Is this assumption correct or not?
since tailrec can't be used in extension functions
Are you sure?
I've just tested it by taking a look at Kotlin bytecode in IntelliJ IDEA. First of all, the code with tailrec on the extension function compiles successfully. Going further: compare the two pieces of Kotlin code and bytecode below, one with tailrec, and the other one without.
Kotlin:
fun Double.tailrecTestExtension(): Double
= (this - 1.0).tailrecTestExtension()
Bytecode:
// access flags 0x19
public final static tailrecTestExtension(D)D
// annotable parameter count: 1 (visible)
// annotable parameter count: 1 (invisible)
L0
LINENUMBER 13 L0
DLOAD 0
DCONST_1
DSUB
INVOKESTATIC com/example/TestKt.tailrecTestExtension (D)D
DRETURN
L1
LOCALVARIABLE $receiver D L0 L1 0
MAXSTACK = 4
MAXLOCALS = 2
Kotlin:
tailrec fun Double.tailrecTestExtension(): Double
= (this - 1.0).tailrecTestExtension()
Bytecode:
// access flags 0x19
public final static tailrecTestExtension(D)D
// annotable parameter count: 1 (visible)
// annotable parameter count: 1 (invisible)
L0
LINENUMBER 13 L0
DLOAD 0
DCONST_1
DSUB
DSTORE 0
GOTO L0
L1
LOCALVARIABLE $receiver D L0 L1 0
MAXSTACK = 4
MAXLOCALS = 2
Notice that in the first example there's INVOKESTATIC call (which corresponds to a regular recursion), which was replaced with a regular jump (GOTO) in the second version (which corresponds to a loop - expected behavior introduced by tailrec).
Note: I'm not an expert in Kotlin bytecode, my understanding is based on some basic knowledge about the assembly language. Here I assume that this knowledge is transferable to Kotlin bytecode.

Value initialization with Kotlin

I think I found a strange fringe case:
What I had:
class Day constructor(cal: Calendar, refCal: Calendar) {
val cal: Calendar
val isBefore: Boolean
val isAfter: Boolean
init {
this.cal = cal.clone() as Calendar
isBefore = 0 < cal.compareTo(refCal)
isAfter = 0 > cal.compareTo(refCal)
}
}
I would instantiate this with two dates, one being a reference, and determine if the date is before or after a reference date. However, what I found on execution is that isBefore and isAfter remained false in some cases, independently of what they should be worth, unless I went in step-by-step with the debugger. So, apparently init was called not right after the constructor, just delayed enough for my values not to be set?
What I did to resolve it was simply calculate isBefore and isAfter in getters:
class Day constructor(cal: Calendar, refCal: Calendar) {
val cal: Calendar
init {
this.cal = cal.clone() as Calendar
this.refCal = refCal.clone() as Calendar
}
val isBefore: Boolean
get() { return 0 < cal.compareTo(refCal) }
val isAfter: Boolean
get() { return 0 > cal.compareTo(refCal) }
}
I'd like to know if my assumption is correct, if there's a way a value can be called before it is initialized with init and if so, if there is a way to mitigate this.
Call example:
fun setDates(refDate: Calendar) {
val cal = Calendar.getInstance()
cal.set(refDate.get(Calendar.YEAR), refDate.get(Calendar.MONTH), refDate.get(Calendar.DAY_OF_MONTH), 0, 0, 0)
cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY)
val monday = Day(cal, refDate)
//...
As far as I know the init block will be executed within the primary constructor, so your original class Day should be fine. You could just remove the init block and assign the values directly with the property's declaration though.
I see just 2 problems, one is:
However, what I found on execution is that isBefore and isAfter
remained false in some cases
That wouldn't be a surprise at all if cal.compareTo(refCal) returned 0. Or if the value of refCal changed between the execution of the 2 lines
isBefore = 0 < cal.compareTo(refCal)
isAfter = 0 > cal.compareTo(refCal)
Second problem is your second Day implementation, when you declare a getter for the property
val isBefore: Boolean
get() { return 0 < cal.compareTo(refCal) }
you're comparing the value each time you read that property, this means that isBefore's value could very easily change within the same Dayinstance, if the value of refCal property changes. If you want just to read the value of refCal and assign isBefore accordingly you should do that when initializing the property, within init block or within declaration (you could also omit the type and use > operator directly):
class Day constructor(cal: Calendar, refCal: Calendar) {
private val cal = cal.clone() as Calendar
val isBefore = cal > refCal
val isAfter = cal < refCal
}
And maybe add property like val isEqual = !isBefore && !isAfter because those 2 are not mutually exclusive.
Update
I just checked with Kotlin 1.2.30, Intellij's Kotlin plugin allows you to see the bytecode of the compile Kotlin class (the action is called "Show Kotlin Bytecode"). The code you put in the init block is indeed executed within the primary constructor. For instance this class:
class Day(cal: Calendar) {
val cal: Calendar
init {
this.cal = cal.clone() as Calendar
}
}
Compiles this constructor:
// access flags 0x1
public <init>(Ljava/util/Calendar;)V
#Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
L0
ALOAD 1
LDC "cal"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
L1
LINENUMBER 3 L1
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
L2
LINENUMBER 8 L2
ALOAD 0
ALOAD 1
INVOKEVIRTUAL java/util/Calendar.clone ()Ljava/lang/Object;
DUP
IFNONNULL L3
NEW kotlin/TypeCastException
DUP
LDC "null cannot be cast to non-null type java.util.Calendar"
INVOKESPECIAL kotlin/TypeCastException.<init> (Ljava/lang/String;)V
ATHROW
L3
CHECKCAST java/util/Calendar
PUTFIELD Day.cal : Ljava/util/Calendar;
L4
RETURN
L5
LOCALVARIABLE this LDay; L0 L5 0
LOCALVARIABLE cal Ljava/util/Calendar; L0 L5 1
MAXSTACK = 5
MAXLOCALS = 2
As you can see the Calendar.clone is called there, so you can treat the init the same way as you would with a constructor in Java.
If you don't have a primary constructor, e.g.:
class Day {
constructor(cal: Calendar)
constructor()
val cal: Calendar
init {
this.cal = Calendar.getInstance()
}
}
2 constructors are created and the code of the init block is executed in each one of them.
// access flags 0x1
public <init>(Ljava/util/Calendar;)V
#Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
L0
ALOAD 1
LDC "cal"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
L1
LINENUMBER 4 L1
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
L2
LINENUMBER 10 L2
ALOAD 0
INVOKESTATIC java/util/Calendar.getInstance ()Ljava/util/Calendar;
DUP
LDC "Calendar.getInstance()"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkExpressionValueIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
PUTFIELD Day.cal : Ljava/util/Calendar;
L3
RETURN
L4
LOCALVARIABLE this LDay; L0 L4 0
LOCALVARIABLE cal Ljava/util/Calendar; L0 L4 1
MAXSTACK = 4
MAXLOCALS = 2
// access flags 0x1
public <init>()V
L0
LINENUMBER 5 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
L1
LINENUMBER 10 L1
ALOAD 0
INVOKESTATIC java/util/Calendar.getInstance ()Ljava/util/Calendar;
DUP
LDC "Calendar.getInstance()"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkExpressionValueIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
PUTFIELD Day.cal : Ljava/util/Calendar;
L2
RETURN
L3
LOCALVARIABLE this LDay; L0 L3 0
MAXSTACK = 4
MAXLOCALS = 1

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