Hey, a little bit of a weird question. But I have ...
# getting-started
h
Hey, a little bit of a weird question. But I have two suspend functions that do the same but one terminates immediately when one subtask fails and the other let's all subtask finish before throwing an Exception. How would you call them so that they don't have the same name? It feels like there is a word for this, but I can't find it.
j
It's hard to provide suggestions without knowing what the functions actually do (because the bulk of the name, or the common part at least, would have to describe that).
But some ideas for the distinction could include a
FailFast
suffix or something like that.
☝️ 1
h
FailFast is nice. It's an iterable.asyncMap function.
s
I do like “fail fast”, but I would hesitate before using it as a modifier suffix since it’s the default behaviour of structured concurrency. It’d feel more natural to have the one with the non-default behaviour be the one that gets the extra suffix.
👍 1
h
FailLazy
? 😄
FailAfterCompletion
👍 1
s
It’s making me thing of the
mapOrAccumulate
function in #arrow. Not sure how I would apply that naming to something that throws exceptions, though.
j
What do consumers of the non-fail-fast version do with the result? What are use cases? It looks like you could just have a fail-fast async map function (as most people would expect), and users who actually need to perform all tasks and then process all possible failures (e.g. a list of task errors) could actually
try-catch
and wrap in a custom result type so they get a list of all results, some of which being errors
💯 1
💡 1
also, I'd rather call it
concurrentMap
or
mapConcurrent
rather than "async", because async doesn't convey the fact that each item is processed concurrently.
asyncMap
could just be a suspend function that still processes all elements sequentially (but suspends until the end of the loop)
In short, I would go for: •
concurrentMap
- processes each element concurrently, fails fast if one element's transform lambda fails. Basically the default behaviour of an implem with `coroutineScope`+`map`+`async`+`awaitAll()` • Optionally, if you do want to streamline the result approach because you have lots of usages, a
concurrentMapCatching
name could be an option (using
runCatching
inside) - but I personally quite dislike using the Kotlin
Result
type directly like this (and would rather encourage applicative code to declare its own result type with a name matching the business, and more importantly catching specific exceptions - not
Throwable
!)
I don't think it's very useful to have a version of the function that just keeps going with the successful processing of each item, and fails at the end with an exception if one or more of them failed. Because likely if you wanted everything to keep going, you probably want to process the failures more gracefully. Hence my suggestion about using a result-like type.
h
Thanks for your input. I will rename it to concurrentMap that is indeed better. I already catch the errors in a custom result type that was what I was going for, actually :D That a mapping can fail is sometimes expected and I just need to display that it happened at all. It's also an edge case that shouldn't happen at all, I just wanted to cover it.
👌 1
That it's expected to fail, but that shouldn't happen at all sounds like an oxymoron.
s
And yet it also sums up the programming concept of an “exception” perfectly 😂
h
True!
j
Yeah if it's an edge case (literally an exception) then why isn't the fail-fast option ok for everything?