<https://medium.com/@sam-cooper/breaking-try-catch...
# feed
d
I knew that try/catch doesn't work normally, but I just didn't think of the finally block and especially the innocent looking
use { }
... thanks!
h
Yeah, it is a known problem of sequence/iterable: It does not support closing a file/resource/calling a close function at all. If you need this, use a flow as you mentioned in your article: https://youtrack.jetbrains.com/issue/KT-54130/Add-onClose-callback-to-Sequence#focus=Comments-27-6459113.0-0
s
Thanks for the YouTrack link!
s
I'm not sure of this isn't an issue with the while(true) situation (in the other situation, it is indeed an issue). In regular/non-suspending code, a try-block with a while(true) loop will never get its finally clause executed either (if no exception happens), since this program will never complete.
s
I did wonder if I should change the example so it doesn't use an infinite loop. Maybe I'll change that. It does make it a bit more complicated. In all of my examples, even when there's a loop, the program does terminate, though.
Thanks for the comment! I removed the infinite loop from the first code example. I think it definitely makes the example simpler and more striking.
e
Java Streams are AutoCloseable, so they are able to handle resource cleanup
kotlinx.coroutines.flow.Flow is closer to a Stream than a Sequence, in that it also supports cancellation. you can still write unreachable code, e.g.
Copy code
flow {
    emit(Unit)
    TODO("unreachable")
}.first()
without as much warning as you do in normal code, but it basically works as expected
on the other hand, Sequence is just a wrapper around Iterator, which doesn't have any ability to handle this
s
👍 I hadn't thought of the comparison with Java streams! I think out of all three (sequence, stream, flow), flows are the most robust, because the call to the collect method creates an inviolable control flow structure. But an autocloseable stream is definitely a decent substitute, and very idiomatic for things like file IO
e
yeah, IMO it becomes clear why it's broken when you realize that
Copy code
sequence { ... }
is basically just
Copy code
iterator { ... }.asSequence()
👍 1
s
Agreed, and personally I think it means the sequence/iterator generators shouldn't have been added. Transforming procedural code that's supposed to have control flow guarantees into a hand-cranked iterator that can't provide those guarantees is too much of a flaw in the language. Though I guess the problem is really with the suspend function transformation itself, not just this one use of it. Anyone could reimplement
iterator { ... }
if they wanted to...
But it sort of feels like it was added mainly because it seemed cool. I've rarely found I actually needed it.
e
there's 3 different places in our production codebase where we lazily traverse a recursive structure and
sequence
has been undoubtedly better than the alternatives for us. it is much more straightforward than writing a state machine for this
Copy code
sequence {
    val queue = ArrayDeque<T>().apply { add(start) }
    while (queue.isNotEmpty()) {
        val node = queue.removeFirst()
        yield(node)
        queue.addAll(node.children)
    }
}
s
In that particular case I don’t think the “low-tech” version is too bad. It gains an advantage by only needing a loop at one end rather than both, so the line count is not that different despite the class boilerplate.
Copy code
class TreeIterator<T>(start: Node<T>): Iterator<Node<T>> {
    private val queue = ArrayDeque<Node<T>>().apply { add(start) }

    override fun hasNext(): Boolean = queue.isNotEmpty()

    override fun next(): Node<T> {
        val node = queue.removeFirst()
        queue.addAll(node.children)
        return node
    }
}
But I do think your version is much more readable. That’s a really nice use of the
sequence
builder and it makes the algorithm instantly recognisable.
s
Also, `Sequence`s are lazy. Not only for their initialization, but also for executing their operators. https://kotlinlang.org/docs/sequences.html#sequence-processing-example