Any significant differences between lambda expressions & anonymous function in Kotlin? - kotlin

Kotlin has these 2 features and I think there're no significant differences between these two
regardless of :
syntax
// lambda
val toUpper = { value: String ->
if (value.isEmpty()) "empty value"
else value.toUpperCase()
}
// anonymous func
val toUpper = fun(value: String): String {
if (value.isEmpty()) return "empty value"
else return value.toUpperCase()
}
flexibility to use return statement on anonymous function
I'm still digesting these features and hope you guys can help me pass through it.
Thanks.

Two differences according to Kotlin Reference:
(I think the more significant one out of the two) An anonymous function is still a function, so returning from it behaves the same as returning from any function. Returning from a lambda, however, actually returns from the function enclosing the lambda.
The return type of a lambda is inferred, while you can explicitly specify a return type for an anonymous function.

This website states: "Lambdas Expressions are essentially anonymous functions that we can treat as values – we can, for example, pass them as arguments to methods, return them, or do any other thing we could do with a normal object." (link)
So the answer is no, there isn't a difference between the two, they are interchangeable. Both of the codes you show above, will in the end return the same value to that variable

Besides the differences pointed by #jingx, you can not local return from a lambda that is not inlined.
So, the next snippet will not compile unless you add inline to the extension() function, thus, instructing the compiler to copy the function's content whenever it is referenced:
fun doSomethingWithLambda(){
10.extension{
if(it == 10)
return//compiler error
}
println("hello")
}
fun Int.extension(f: (Int)->Unit){
f(this)
}

Related

When do I use another function without paramters in Kotlin?

I'm a novice of Kotlin.
I found that I can use another function without parameters even if it has.
Let me know when I can use it.
Q1) Why can I use 2 types? (with parameters & without parameters) Is it Kotlin's feature?
Q2) What does it mean? ((Result!) -> Unit)!
It seems you are confused, you can never use a function without arguments. If the function has arguments then you have to fill the slot somehow.
The closest thing that could relate to what you are referring to is default values for arguments.
fun example(boolean: Boolean = true) {}
example()
example(true)
example(false)
You can omit the argument because it has defaulted in the function signature.
The documentation
What you are showing in the image file is a lambda.
In the first example:
signIn(listener: Session...)
That seems to be a callback. So it is gonna be an interface or maybe an abstract class called when some async operation is finished.
The second example, it is the callback implemented as a lambda
signIn() { result ->
//do something
}
In Kotlin the last argument if it is a lambda or something that can be implemented as a lambda can be moved out of the parenthesis for syntactic sugar. A lambda is like an anonymous function, it is a literal of a function.
By example you can declare a lambda:
val lambda = {text: String -> text.lenght % 2 == 0}
fun setRuleForText(rule: (String)-> Boolean) {...}
setRuleForText(lambda)
setRuleForText() { text: String
text.isNotEmpty()
}
In this case, the argument is a kotlin function. The argument rule is a function that receives a String as an argument and returns Boolean. Something to point out is that expressions return the last written value without the need for the reserved return word.
This is the documentation. And here you can see from a good source more about functions (the author is a Kotlin certified trained by Jetbrains)
In your case (Result) -> Unit means the lambda should receive a Result type as argument and then return Unit (unit is like void in Java but is more than that), no explicit return type.
signIn() { result ->
//do something
}
Most of the types, the argument on lambdas is inferred automatically, but if not, then
signIn() { result: Result ->
//do something
}
Both of the listed functions take a parameter.
The first is:
signIn(listener: Session.SignInListener!)
That takes a single parameter, of type Session.SignInListener.  (The ! means that Kotlin doesn't know whether it's nullable or not, because it's from Java and isn't annotated.)
The other is:
signIn {...} (listener: ((Result!) -> Unit)!)
That's the IDE's representation of the function with this signature:
signIn(listener: ((Result!) -> Unit)!)
That takes a single parameter, which is a function type (see below).
The reason the IDE shows it with braces is that in Kotlin, if the last parameter to a function is a lambda, you can move it outside the parentheses.  So a call like this:
signIn({ println(it) })
could equally well be written like this:
signIn() { println(it) }
The two forms mean exactly the same.  And, further, if the lambda is the only parameter, you can omit the parens entirely:
signIn { println(it) }
Again, it means exactly the same thing.
That syntax allows you to write functions that look like new language syntax.  For example:
repeat (10) {
// ...
}
looks like a new form of loop construct, but it's really just a function called repeat, which takes two parameter (an integer, and a lambda).
OK, let's look at that function type: ((Result!) -> Unit)!
That's the type of a function which takes one parameter of type Result, and returns Unit (i.e. nothing useful; think of it as the equivalent of void).  Again, it's complicated because Kotlin doesn't know about the nullability; both the Result parameter and the parameter holding this function have !s to indicate this.  (Without them, it would just be (Result) -> Unit.)

Kotlin fun() vs lambda is there difference?

This question is about fun() vs a lambda block definitions and scopes.
i have tried define the expressions in two ways. Here is what i have tried:
val myFunction = fun(){
println("i am in a function")
}
//but i also tried doing this:
val myFunction = {
println("i am in a lambda")
}
my problem is i do not know if they are equivalent and same thing ?
The differences are best described in https://kotlinlang.org/docs/reference/lambdas.html#anonymous-functions:
Anonymous functions allow you to specify return type, lambdas don't.
If you don't, return type inference works like for normal functions, and not like for lambdas.
As #dyukha said, the meaning of return is different:
A return statement without a label always returns from the function declared with the fun keyword. This means that a return inside a lambda expression will return from the enclosing function, whereas a return inside an anonymous function will return from the anonymous function itself.
There is no implicit it parameter, or destructuring.
Your specific cases will be equivalent, yes.
See the reference: https://kotlinlang.org/docs/reference/lambdas.html
There are several ways to obtain an instance of a function type:
Using a code block within a function literal, in one of the forms:
a lambda expression: { a, b -> a + b },
an anonymous function: fun(s: String): Int { return s.toIntOrNull() ?: 0 }
Both give you a function object which can be used interchangeably

Using implicit variable in function literal

I started reading Kotlin course book. I stopped on function literals. Here I have a code:
val printMessage = { message: String -> println(message) }
printMessage("hello")
printMessage("world")
Then I have an information that I can omit parameter type:
{ message -> println(message) }
And now I have next step:
"In fact, Kotlin has a neater trick. If there is only a single parameter and the type can beinferred, then the compiler will allow us to omit the parameter completely. In this case, itmakes the implicit variable it available:
{println(it)}
And now after using this code I get an error "unresolved reference: it" and "too many arguments for public operator fun invoke(): ??? defined in kotlin.Function()":
val printMessage = {println(it)}
printMessage("print something")
My question is how to use implicit variable in single paramenter function literal?
See the Kotlin documentation, specifically where it says:
If the compiler can figure the signature out itself, it is allowed not
to declare the only parameter and to omit ->. The parameter will be
implicitly declared under the name it.
In your case, the compiler (at least up to current version 1.3.31) can't figure the signature out itself:
val printMessage = {println(it)}
But if you give your printMessage variable an explicit type, it will work:
val printMessage: (String) -> Unit = { println(it) }
You always need to provide all information about all generic parameters. If you want to omit it, it needs to be inferable from some other part of the code. The only information you provide though is that you want printMessage to be a lambda. So it assumes it to be of type ()->Unit. This is because you don't declare a parameter for the lambda itself. The implicit parameter it is therefore not usable.
val printMessage = { it: String -> println(it) }
val printMessage: (String)->Unit = { println(it) }
Simply put: If you're inside a lambda with one parameter, the implicit it can be used as this parameters name, but a reference named it within the body of the lambda doesn't declare the single parameter.

Compilation error: Smart cast to '<type>' is impossible, because '<variable>' is a local variable that is captured by a changing closure

To simplify my real use case, let's suppose that I want to find the maximum number in a list:
var max : Int? = null
listOf(1, 2, 3).forEach {
if (max == null || it > max) {
max = it
}
}
However, compilation fails with the following error:
Smart cast to 'Int' is impossible, because 'max' is a local variable that is captured by a changing closure
Why does a changing closure prevent smart cast from working in this example?
In general, when a mutable variable is captured in a lambda function closure, smart casts are not applicable to that variable, both inside the lambda and in the declaring scope after the lambda was created.
It's because the function may escape from its enclosing scope and may be executed later in a different context, possibly multiple times and possibly in parallel. As an example, consider a hypothetical function List.forEachInParallel { ... }, which executes the given lambda function for each element of the list, but in parallel.
The compiler must generate code that will remain correct even in that severe case, so it doesn't make an assumption that the value of variable remains unchanged after the null check and thus cannot smart cast it.
However, List.forEach is quite different, because it is an inline function. The body of an inline function and the bodies of its functional parameters (unless the parameter has noinline or crossinline modifiers) are inlined at the call site, so the compiler could reason about the code in a lambda passed as an argument to inline function as if it was written directly in the calling method body making the smart cast possible.
It could, but currently, it doesn't. Simply because that feature is not implemented yet. There is an open issue for it: KT-7186.
Thanks to Ilya for the detailed explanation of the problem!
You can use the standard for(item in list){...} expression like this:
var max : Int? = null
val list = listOf(1, 2, 3)
for(item in list){
if (max == null || item > max) {
max = item
}
}
This looks like a compiler bug to me.
If the inline lambda parameter in forEach were marked as crossinline then I would expect a compilation error because of the possibility of concurrent invocations of the lambda expression.
Consider the following forEach implementation:
inline fun <T> Iterable<T>.forEach(crossinline action: (T) -> Unit): Unit {
val executorService: ExecutorService = ForkJoinPool.commonPool()
val futures = map { element -> executorService.submit { action(element) } }
futures.forEach { future -> future.get() }
}
The above implementation would fail to compile without crossinline modifier. Without it, the lambda may contain non-local returns which means it cannot be used in a concurrent fashion.
I suggest creating an issue: Kotlin (KT) | YouTrack.
The problem is that foreach creates multiple closures, each of which access the same max which is a var.
What should happen if max were set to null in another of the closures after the max == null check but before it > max?
Since each closure can theoretically work independently (potentially on multiple threads) but all access the same max, you can't guarantee it won't change during execution.
As this is in the top results for the error Smart cast to '<type>' is impossible, because '<variable>' is a local variable that is captured by a changing closure here is a general solution that worked for me (even if the closure is not inlined):
Sample showing this error:
var lastLine: String? = null
File("filename").useLines {
lastLine = it.toList().last()
}
if(lastLine != null) {
println(lastLine.length) // error! lastLine is captured by the useLines closure above
}
Fix: Create a new variable that is not captured by the closure:
var lastLine: String? = null
File("filename").useLines {
lastLine = it.toList().last()
}
val finalLastLine = lastLine
if(finalLastLine != null) {
println(finalLastLine.length)
}

How to define a oneline function calling a nullable variable function

If I have something like:
fun showProgressView() = ultraRecyclerView?.showProgressBar()
it says that it returns Unit? and not Unit (edited)
-----EDIT-----
One way can be
fun showProgressView() = ultraRecyclerView?.showProgressBar() ?: Unit
but it looks not right for me.
Another way:
fun showProgressView() { ultraRecyclerView?.showProgressBar() }
But I cant find a way for android studio maintain that format.
If you use the short expression form of a function, the inferred result type of the expression determines the function return type. If that is a platform type from Java, it could be nullable. If it is a Kotlin type then it will know the correct nullability.
But since you use the safe operator ?. you are saying for sure it could be nullable. And if the result is null or Unit then that gives the inferred result type of Unit?
Which is odd, but is exactly what you are saying. Therefore, either use a normal function body with { .. } or give the function an explicit return type if possible.
fun showProgressView(): Unit { ultraRecyclerView?.showProgressBar() }
You can also erase the nullability, by creating an extension function on Unit?:
fun Unit?.void() = Unit
And use it whenever you want to fix the return type:
fun showProgressView() = ultraRecyclerView?.showProgressBar().void()
IntelliJ IDEA / Android Studio do not appear to have a setting to keep the style of a block body function on a single line. Even so, you can use run to get around this:
fun showProgressView() = run<Unit> { ultraRecyclerView?.showProgressBar() }
Normally you do not need to add explicit type arguments to run but in this case providing them gives you the desired method signature (return type of Unit and not Unit?).
Note: This answer is adapted from a comment I gave to why assignments are not statements.