Hi folks! Is there a functional way to write this?...
# announcements
i
Hi folks! Is there a functional way to write this?
Copy code
for (handler in handlers) {
    if (handler.handle(uri)) break
}
s
handlers.any { it.handle(uri) }
maybe?
But mixing functional style with sideeffects is a bit nasty
d
.find {}
would also work
I agree with Johannes though
s
Maybe
Copy code
handlers.takeWhile { !it.handle(uri) }
1
Or, if it is all side-effect related:
Copy code
handlers.forEach { 
    if (it.handle(uri)) return@outerScope 
}
s
I would prefer the break version to the last one ;-)
In general I dont understand why people go to such lengths to avoid a simple for loop
i
yeah,
break
version seems actually better 🙂
I should have added functional way that makes sense 😉 agree that functional for the sake of it is not good!
b
In general I dont understand why people go to such lengths to avoid a simple for loop
Answer #1: which is easier to read? The
for
loop or
handlers.find { it.handle(uri) }
? Answer #2: Assuming handlers have side-effects, then lurking under that for loop is the possibility of an unlimited number of side-effects. So instead of being able to look at just the for loop to determine where an error lies the entire application may need to be deconstructed to find it. With those unconstrained effects comes an inability to usefully and completely test the code in question since there are now no rules about what can actually happen in that for loop. Unit and integration testing likely cannot cover all possible side-effects. Writing the code as a tail-recursive find in an effect management system (such as Arrow) constrains the side-effects to be well-defined, proven correct-by-construction by the compiler, and requires only property-based tests to test - specifically, the property that at most a single handler is run.
i
but in this case
find
isn't semantically correct
and it doesn't help with the side effects as it's performing them anyway?
c
In a pure-functional language, the compiler does impose certain constraints about side-effects. But Kotlin is not pure-functional, and as such there is nothing inherently “safer” about using
.find
as-opposed to a for-loop. You can cause the exact same kinds of side effects in both, but in the
.find
case it’s harder to even know that side-effects are happening. With a for-loop, running code and breaking in the middle is much more obvious what’s going on. In the
find
case, it kind-of looks like the values have been precomputed, when in reality its computing them right there with the possibility of causing side-effects