7

I noticed that I get the same effect if I define this trivial function:

fun double ( i: Int ) = i*2

and if I define a variable and assign a lambda (with an identical body) to it:

var double = { i : Int -> i*2 }

I get the same result if I call double(a) with either declaration. This leaves me confused. When is it needed, recommended, advantageous to define a variable as a lambda rather than define a function to it?

3
  • 1
    in the case you mention I think the most difference obvious would be that you can give any body to the lambda, but you cannot change the body of a function. This is basically a question of what is lambda, isn't it? Commented Oct 17, 2018 at 7:54
  • I don't understand your question. You're comparing a function with a variable. Obviously they both have their uses Commented Oct 17, 2018 at 7:57
  • One of the usages is to use them in inline functions. Commented Oct 17, 2018 at 8:10

5 Answers 5

13

When is it needed, recommended, advantageous to define a variable as a lambda rather than define a function to it?

Whenever you have the choice of either, you should use a fun declaration. Even with a fun you can still get a first-class callable object from it by using a function reference.

On the JVM, a fun is significantly more lightweight, both in terms of RAM and invocation overhead. It compiles into a Java method, whereas a val compiles into an instance field + getter + a synthetic class that implements a functional interface + a singleton instance of that class that you must fetch, dereference, and invoke a method on it.

You should consider a function-typed val or var only when something is forcing you to do it. One example is that you can dynamically replace a var and effectively change the definition of the function. You may also receive function objects from the outside, or you may need to comply with an API that needs them.

In any case, if you ever use a function-typed property of a class, you'll know why you're doing it.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks. I was following the "Kotlin bootcamp" course on Udacity, and it brought up this example without really entering into these 'details'. Very helpful.
Very nice answer, very informative! Where did you get this information? Have you read it in some book or similar? Or did you inspect the bytecode on your own? I am always interested on how to find out how stuff works under the hood in different languages. :)
@MarkusWeninger It's a combination of getting familiar with the semantics of Kotlin properties and using the IDEA built-in "show kotlin bytecode" feature.
4

First, if I understand you right, your question is "Why are functions first-class citizens in Kotlin -- And when to use them as such?", right?

Kotlin functions are first-class, which means that they can be stored in variables and data structures, passed as arguments to and returned from other higher-order functions. You can operate with functions in any way that is possible for other non-function values. (see here)


As stated in the docs, one use case are higher-order functions. As a first step, I will leave the wikipedia link here: https://en.wikipedia.org/wiki/Higher-order_function

Basically, a higher-order function is a function that takes functions as parameters, or returns a function. This means that a higher-order function has at least one parameter of a function type or returns a value of a function type.

Following a short example of a higher-order function that receives a parameter of function type (Int) -> Boolean:

fun foo(pred: (Int) -> Boolean) : String = if(pred(x)) "SUCCESS" else "FAIL"

This higher-order function can now be called with any (Int) -> Boolean function.


The docs also state ... [can be used] in any way that is possible for other non-function values.

This means that you can, for example, assign different functions to a variable, depending on your current context.

For example:

// This example is verbose on purpose ;)
var checker: (Int) -> Boolean
if (POSITIVE_CHECK) {
    checker = { x -> x > 0 } // Either store this function ...
} else {
    checker = { x -> x < 0 } // ... or this one ...
}
if (checker(someNumber)) { // ... and use whatever function is now stored in variable "checker" here
  print("Check was fine")
}

(Code untested)

2 Comments

Is his var double and his fun double exactly the same under the hood?, is it just syntax that differentiates them?
@Adam: No, in general a fun is more lightweight. (See also @Marko Topolnik's answer). Just a minimal explaination: A val or var is an object on the heap, i.e., taking up memory, and so are variables of function types. A fun is a function, an is part of the class description stored internally in the JVM.
2

You can define variable and assign it lambda when you want change behaviour for some reason. For example, you have different formula for several cases.

val formula: (Int) -> Int = when(value) {
    CONDITION1 -> { it*2 }
    CONDITION2 -> { it*3 }
    else -> { it }
}
val x: Int = TODO() 
val result = formula(x)

If you simply need helper function, you should define it as fun.

Comments

1

If you pass a lambda as a parameter of a function it will be stored in a variable. The calling application might need to save that (e.g. event listener for later use). Therefore you need to be able to store it as a variable as well. As said in the answer however, you should do this only when needed!

Comments

0

For me, I would write the Lambda variable as followed:

var double: (Int) -> Int = { i ->    //no need to specify parameter name in () but in {}
    i*2 
}

So that you can easily know that its type is (i: Int) -> Int, read as takes an integer and returns an integer.

Then you can pass it to somewhere say a function like:

fun doSomething(double: (Int) -> Int) {
    double(i)
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.