is `return@` considered harmful or unidiomatic? fo...
# getting-started
y
is
return@
considered harmful or unidiomatic? for example, I want to make a function that sums up the number of values of a list, or returns
null
if a certain value is detected. I wrote it as
Copy code
fun List<Foo>.calcSum() = this.fold(0) { sum, val -> if (something) { sum + val } else { return@calcSum null } }
is this bad style? I had to add a type hint for the function to even compile.
v
That does not even compile, so I'd say it is bad style šŸ˜„
But even if I replace the invalid
val
by
value
and replace the undefined types to have
Copy code
fun List<Int>.calcSum() = this.fold(0) { sum, value -> if (kotlin.random.Random.nextBoolean()) { sum + value } else { return@calcSum null } }
I get
Type mismatch: inferred type is Int but Nothing? was expected
Besides that I think that the
@calcSum
is redundant here as a simple
return
would have the same effect.
Ah, with an explicit return type it works
Copy code
fun List<Int>.calcSum(): Int? = this.fold(0) { sum, value -> if (kotlin.random.Random.nextBoolean()) { sum + value } else { return null } }
while I personally would use an extension property
Copy code
val List<Int>.sum: Int? get() = this.fold(0) { sum, value -> if (kotlin.random.Random.nextBoolean()) { sum + value } else { return null } }
But that of course says nothing about idiomaticness šŸ˜•
j
It has its place but in most cases its preferred to use the implied return we get from the last line of the lambda expression
plus1 1
y
@Vampire yep, the explicit return type is what I meant by adding a type hint. heh. an alternative to this syntax is a fold that returns a sentinel value, maybe
-1
, followed by a
.takeIf { it >= 0 }
k
But that would still iterate the whole list instead of short-circuiting.
y
oh yeah, I forgot to mention it would still require
return@
, except it would return from the
fold
rather than the function. all in all, not an improvement. this is a problem that requires either two passes (one pass to verify input, second pass to sum) or one pass with short-circuiting. I do think
return@
is the right solution here.
t
Copy code
fun List<Foo>.calcSum() = 
if (!something) null
else this.fold(0) { sum, val -> sum + val }
can’t something like this work? or is
something
depending on
val/sum
? (I find it more readable, don’t know about idiomatic)
y
@thanksforallthefish the issue here is that the
something
is a property of one of the values so it is discovered on-the-fly. for example if
Foo
is a
sealed class
with one ā€œnumberā€ variant and one ā€œnot a numberā€ variant, and you want to sum a
List<Foo>
such that a sum is
null
if any of the values is not a number.
I guess I can also write my own
fold
function with a closure that allows short-circuiting.
j
I thought that a return in a lambda expression by default goes to the outer function. You only need a label if you're trying to return a value for the fold to pick up.
y
oh, that seems right to me - good point. I’m used to another language where this is not the case. edit: it does work like that.
m
return@
has its usages, mostly for returning from lambdas to enclosing functions https://kotlinlang.org/docs/returns.html#return-to-labels
šŸ‘ 1