Hey guys I’m a bit confused of how local return works in Kotlin. My expectation was that, after running the code below, as soon as the condition is met, it will immediately print End of loop, however the loop will still run for all elements and then print that text. Can some please clarify how does a local return work in this context?. Thanks
fun localReturn(list: List<String>) {
var counter = 1
list.forEach {
println(it)
if (counter == 3) {
println("counter == 3")
return@forEach
}
counter++
}
println("End of loop")
In this example, the loop itself lives inside the forEach function, and on every step of the loop it calls into the lambda that you pass to it. The return returns from the lambda, so it interrupts execution of the current loop step, but there is no way for it to influence the execution of the loop itself.
Here’s an equivalent way to rewrite your example without using a lambda:
var counter = 1
fun localReturn(list: List<String>) {
list.forEach {
loopBody(it)
}
println("End of loop")
}
fun loopBody(element: String) {
println(element)
if (counter == 3) {
println("counter == 3")
return
}
counter++
}
fun main(args: Array<String>) {
localReturn(listOf("1", "2", "3", "4", "5", "6"))
}
fun main(args: Array<String>) {
val list = listOf("1", "2", "3", "4", "5", "6")
var counter = 1
run {
list.forEach {
println(it)
if (counter == 3) {
println("counter == 3")
return@run
}
counter++
}
}
println("End of loop")
}
Output:
1
2
3
counter == 3
End of loop
I need to use the method “run” as a label, as a real label crashes the compiler:
fun main(args: Array<String>) {
val list = listOf("1", "2", "3", "4", "5", "6")
var counter = 1
label@
list.forEach {
println(it)
if (counter == 3) {
println("counter == 3")
return@label
}
counter++
}
println("End of loop")
}
Error:Kotlin: [Internal Error] org.jetbrains.kotlin.codegen.CompilationException: Back-end (JVM) Internal error: Argument for @NotNull parameter ‘descriptor’ of org/jetbrains/kotlin/codegen/state/KotlinTypeMapper.mapReturnType must not be null
PsiElement: println(it)
if (counter == 3) {
println(“counter == 3”)
return@label
}
counter++
The root cause was thrown at: KotlinTypeMapper.java:-1
at org.jetbrains.kotlin.codegen.ExpressionCodegen.genQualified(ExpressionCodegen.java:325)
…
the following code gives the required output, only difference is using return instead of return@forEach, can you please explain the reasoning behind this
/**
* You can edit, run, and share this code.
* play.kotlinlang.org
*/
fun main() {
println("Hello, world!!!")
localReturn(listOf(1,2,3,4,5))
}
fun localReturn(list: List<Int>) {
var counter = 1
list.forEach {
println(it)
if (counter == 3) {
println("counter == 3")
return
}
counter++
}
println("End of loop")
}
The difference is return vs return@forEach. forEach code is inlined into your localReturn function, so when you put the return keyword, it returns from the localReturn function, rather than the forEach function.