Kotlin: Whats Does "Return@" Mean

Kotlin: Whats does return@ mean?

In Kotlin, the return@label syntax is used for specifying which function among several nested ones this statement returns from.

It works with function literals (lambdas) and local functions. Non-labeled return statements return from the nearest (i.e. innermost) enclosing fun (ignoring lambdas). Consider this function:

fun foo(ints: List<Int>) {
ints.forEach {
if (it == 0) return
print(it)
}
}

Here, return will finish the execution of foo, not just the lambda.

But if you want to return from any other function (a lambda or an outer fun) you have to specify it as a label at return statement:

fun foo(ints: List<Int>) {
ints.forEach {
if (it == 0) return@forEach // implicit label for lambda passed to forEach
print(it)
}
}

fun foo(ints: List<Int>): List<String> {
val result = ints.map f@{
if (it == 0) return@f "zero" // return at named label
if (it == -1) return emptyList() // return at foo
"number $it" // expression returned from lambda
}
return result
}

foo(listOf(1, -1, 1)) // []
foo(listOf(1, 0, 1)) // ["number 1", "zero", "number 1"]

Non-local return (i.e. return from outer functions) from a lambda is only supported for local and inline functions, because if a lambda is not inlined (or a function is placed inside an object), it is not guaranteed to be called only inside the enclosing function (e.g. it can be stored in a variable and called later), and the non-local return would make no sense in this case.


There is also a similar syntax for qualified this, which is used to reference receivers of outer scopes: this@outer.

Kotlin clarification about @ symbol and return postfixes

  1. What does exactly do placing the postfixes "async" and "lazy" after a "return"?

This is not special syntax in Kotlin with the specific words "async" or "lazy". So it is not really a "postfix for the return keyword". After a space, what follows the return is always the value that you want to return:

  • return 42 returns the value 42
  • return async returns the value of the expression async (which is probably a variable that has been declared earlier in the code)
  • return async { 42 } returns the value of the expression async { 42 }.

The meaning of the expression async { 42 } here is unrelated to the return in itself. You could see the same expression assigned to a variable for instance: val deferred = async { 42 }. async is simply a library function from the kotlinx.coroutines library (it's just my guess by the way, maybe the code you've seen declares variables/functions of this name, but it's hard to tell without more context). Have a look at the doc of the async function here if you're interested.


  1. What does the "@" symbol mean here?

The return keyword by default returns from the closest enclosing function declared with the fun keyword. Lambdas don't count, because they are not declared with fun.

Therefore, return-ing from inside a lambda will by default (without @) return from an enclosing function rather than just the "local" lambda (as opposed to what happens in Java). This is why we call them non-local returns.

Using a qualified return with a label (return@label) allows to change this default behaviour and specify what you want to return from explicitly.
See the doc about return at labels, it contains many examples.

The specific examples you gave:

return@async
return@lazy
return@withContext

would need a bit more context to understand them. But I assume that you have seen them used inside lambdas that are a parameter of async/lazy/withContext function calls. What follows the @ here is called an implicit label which tells the compiler that this return is supposed to return from this lambda instead of returning from the closest enclosing fun.

Other notes

Note that the @ symbol here is not an annotation like you could see elsewhere like @JvmDefault or @OptIn(...), it is instead a label reference.

Note that both a label and a return value can be combined: return@myLabel 42 returns the value 42 from the function qualified by the label myLabel.

What is the purpose of Unit-returning in functions

The purpose is the same as C's or Java's void. Only Unit is a proper type, so it can be passed as a generic argument etc.

  1. Why we don't call it "Void": because the word "void" means "nothing", and there's another type, Nothing, that means just "no value at all", i.e. the computation did not complete normally (looped forever or threw an exception). We could not afford the clash of meanings.

  2. Why Unit has a value (i.e. is not the same as Nothing): because generic code can work smoothly then. If you pass Unit for a generic parameter T, the code written for any T will expect an object, and there must be an object, the sole value of Unit.

  3. How to access that value of Unit: since it's a singleton object, just say Unit

What's the deal with `return` followed by @ and reference to outer block?

This is a way to say that the return is just from the wihtContext block.

The '@' is a simply a label and it can be explicit, e.g. return @yourOwnLabel, or implicit e.g, return@withContext, return@forEach etc.

There is more info in the Kotlin documentation here: https://kotlinlang.org/docs/returns.html#return-to-labels

Here is an example with an explicit label from the link above (with the label name modified to make it more obvious):

fun foo() {
listOf(1, 2, 3, 4, 5).forEach myLabel@{
if (it == 3) return@myLabel // local return to the caller of the lambda - the forEach loop
print(it)
}
print(" done with explicit label")
}

What does Void return type mean in Kotlin

Void is a plain Java class and has no special meaning in Kotlin.

The same way you can use Integer in Kotlin, which is a Java class (but should use Kotlin's Int). You correctly mentioned both ways to not return anything. So, in Kotlin Void is "something"!

The error message you get, tells you exactly that. You specified a (Java) class as return type but you didn't use the return statement in the block.

Stick to this, if you don't want to return anything:

fun hello(name: String) {
println("Hello $name")
}

How return@map works

Given

.map { t, u ->
t.let {
val featuredIn = FeaturedIn(it.get("id") as Int, it.get("movie_title") as String, it.get("make_year") as Int)
val celeb = MovieCeleb(it.get("celeb_id") as Int, it.get("full_name") as String, it.get("birth_date") as LocalDate, featuredIn)
return@map celeb
}
}

return@map celeb will return celeb reference value from map function (not from let!). It is just some kind of so-called non-local return, whereas you can manually specify the return scope of your statement.

Using return inside a lambda?

Just use the qualified return syntax: return@fetchUpcomingTrips.

In Kotlin, return inside a lambda means return from the innermost nesting fun (ignoring lambdas), and it is not allowed in lambdas that are not inlined.

The return@label syntax is used to specify the scope to return from. You can use the name of the function the lambda is passed to (fetchUpcomingTrips) as the label:

mainRepo.fetchUpcomingTrips { trips ->
if (trips.isEmpty()) {
showEmptyViews()
return@fetchUpcomingTrips
}

// ...
}

Related:

  • Return at labels in the language reference

  • Whats does “return@” mean?



Related Topics



Leave a reply



Submit