The inconsistency is actually the source of distress and bugs.
In our experience, developers donât know where to put return
. Consider this (option 1):
fun foo(...) {
// large block
bar {
// large block
return baz
}
}
versus (option 2):
fun foo(...) {
// large block
return bar {
// large block
baz
}
}
Which is extremely common in Kotlin. We found that developers will put return randomly between these two options. So hereâs a common pitfall:
- Developer A implements
bar
but forgets crossinline
.
- Developer B implements
foo
which uses bar
and places return
as in the option 2.
This easily creates a bug and wastes thousands of dollars and precious human lives are lost.
The dilemma doesnât exist if return
is always required (JavaScript):
fun foo(...) {
// large block
return bar {
// large block
return baz
}
}
Here they have to pace return
at both points. Or, if return
is completely optional (ideal Kotlin):
fun foo(...) {
// large block
bar {
// large block
baz
}
}
So, inconsistency itself is a huge problem.
Let me point out another example of distress:
fun foo(...) {
// large block
return baz
}
So far so good. But letâs wrap it up with bar
(again, extremely common in Kotlin):
fun foo(...) = bar {
// large block
baz
}
So now it is required to make a change to remove return
on a completely unrelated line! This messes up blame big time. If again bar
is removed, which is often, then the developer has to go back and see where they need to add return.
I donât see how any âclarityâ is achieved by adding this 6 character word when its place is always at the last expression. Or, isnât in case of a lambda.
This change would be completely backward compatible since we would only make return
optional. If you prefer to use it, fine, and this can be achieved with IDE (âinspectionsâ).