Open yole opened 8 years ago
Simple collection operations inside nested lambdas are ok to use it
in:
appendCommaSeparated(properties) { props ->
props.map {it.name}
}
To improve readability, multiline single-argument lambdas should also always name the argument instead of using it
, since it
can become unclear in longer lambdas.
// Good
appendCommaSeparated(properties) { prop ->
val propertyValue = prop.get(obj) // ...
}
// Bad
appendCommaSeparated(properties) {
val propertyValue = it.get(obj) // ...
}
what about the case where the method has multiple function args like with RxJava's subscribe method?
someObservable.subscribe { next -> doThing(next) }
someObservable.subscribe({ next ->
doThing(next)
}) { error ->
error.printStackTrace()
}
someObservable.subscribe({ next ->
doThing(next)
}, { error ->
error.printStackTrace()
}) {
logger.logStreamCompletion()
}
Seems to me that once there are multiple lambda arguments, forcing the last one outside of the parenthesis may not be desirable?
someObservable.subscribe({ next ->
doThing(next)
}, { error ->
error.printStackTrace()
}, {
logger.logStreamCompletion()
})
@trevjonez I think at that point it is a better option to use named arguments without trailing lambdas, that way you don't confuse lambda order and keep it readable
I do think we both agree that we want to optimize for reading clarity.
Anymore I find I always put it inside parenthesis when a follow up call might look ambiguous as to what it operates on to those with less context of the code.
again with an rxjava usecase as an example.
someSingle().subscribe({ doThings(it) }) { error ->
logger.log(error)
throw error
}.trackInMap(someMap, someKey)
is trackInMap
operating on the lambda or on the result of subscribe?
Lets adjust the parens and see if it is more clear:
someSingle().subscribe({ doThings(it) }, { error ->
logger.log(error)
throw error
}).trackInMap(someMap, someKey)
the compiler can solve it fine either way, but for us humans that parenthesis disambiguates with minimal mental effort.
Hrmm to be a bit more specific, I think the best practice in this case is to wrap it with an extension function that allows you to use named arguments.
Just like RxKotlin does with subscribeBy
.
Because now you can do
someSingle().subscribeBy(
onSuccess = { result -> doThings(result) },
onError = { throwable ->
logger.log(throwable)
throw throwable
})
Now you definitely won't get confused about which lambda is for what.
When possible, put lambdas on a single line, using
it
for single-parameter lambdas:Don't use
it
in nested lambdas; always declare parameter names explicitly.When declaring parameter names in a multiline lambda, put the names on the first line, followed by the arrow and the newline: