Consider this code:
type
A = tuple [iterate: iterator() : int]
proc newA(): A =
echo "creating"
iterator stuff(): int {.closure.} =
yield 1
yield 2
result = (iterate: stuff)
for i in newA().iterate():
echo i
I would expect to see
creating
1
2
Under nim-0.13, I get:
creating
creating
1
creating
creating
1
creating
creating
1
...
infinitely. Can anyone explain this behavior to me? It doesn't fit with the principle of least surprise. Maybe I can reduce it down further. I'll give it a shot.
Eliminating a tuple that isn't necessary:
proc newA(): iterator(): int =
echo "creating"
iterator stuff(): int {.closure.} =
yield 1
yield 2
result = stuff
for i in newA()():
echo i
I would consider this to be a bug, albeit a understandable (and hard to fix) one.
The problem here is that your for loop is being transformed into this (translated from the C output):
while true:
var i = 0
var tempOne = newA()
i = tempOne()
var tempTwo = newA()
if finished(tempTwo):
break
echo(i)
Moving the call to newA into a variable before the loop, like ''var temp == newA();for i in temp()`` causes this code to be generated instead:
var temp = newA()
while true:
var i = temp()
if finished(temp):
break
echo i
This looks like some sort of weird interaction in the Nim compiler between the lambda lifting code, the closure iterator generating code, and the for loop generating code.