During reading mastering Nim I found that I do not fully understand the closure iterators
I think that the main magic for me was mentioned in "resumable function" I cannot undertand
I created some playground: https://wandbox.org/permlink/zDz2jv0Z9aaJo4Jy
iterator ab(a, b: int): int {.closure.} =
for x in a..b:
yield x
proc f(it: iterator) =
echo it(1, 4)
echo it(1, 4)
echo it(1, 2)
echo it(1, 4)
f(ab)
Result is
1
2
0
0
I see than initialization happens during first call of it, after it iterator falls into for. But my brain absolutely blowing that the 3rd pass of the (1, 2) brakes for somehow iterator entered already and forces it finish
How is it possible?
Closure iterators not using a generator require passing in the state, when you pass in 1, 2 it finishes the iterator since it already iterated to 2.
The 'proper' way of doing what you want is to write a closure generator that stores the state on instantiation:
proc makeMyClos(a, b: int): iterator: int =
result = iterator: int {.closure.} =
for x in a..b:
yield x
proc f(it: iterator) =
echo it()
echo it()
echo it()
echo it()
f(makeMyClos(1, 4))
This stores the creation state with the iterator so one does not need to pass the data and is a more understandable construct. Not that there is no use case for a normal iterator. (My Package Slicerator contains a asClosure macro that handles this automatically
Without it you have to provide the environment every time, if you change the parameters value it will finish early. Once finished it does not run the code. That's what finished means.
echo it(1, 4) # not finished, prints 1
echo it(1, 4) # not finished, prints 2
echo it(1, 2) # finished, prints 0 due to being finished
echo it(1, 3) # still finished
It is still feels strange for me how the yeild updates outer values and the resumable magic
Can I think about it like: closure which updates scope every call and continue from yield?