-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Defer in iterators is only guaranteed if the iterator runs to completion #11815
Comments
Your iterator is in global scope so it has the lifetime of your program and is never collected. However this also occurs when the iterator has a shorter lifetime: proc count(n: int): iterator(): int =
return iterator(): int =
defer: echo "Defer was executed!"
for i in 1..n:
yield i
proc main() =
let it = count(10)
for i in 1..5:
echo $it()
main()
echo "the end" |
Well, this works iterator readLines(filename: string): string =
var f = open(filename, fmRead)
defer:
echo "close"
f.close()
for line in lines(f):
yield line
proc head(filename: string, n: int): seq[string] =
var i = 0
for line in readLines(filename):
if i >= n:
break
echo "line: ", line
result.add line
i += 1
let xxx = head("input", 10)
echo xxx
output:
|
@krux02 - I don't know if that's doing what you think it's doing; you're calling |
sorry, there was a line that I did not remove properly. I fixed the comment now. I know it is not perfect, but it does work. |
@krux02 - While I get that your example is showing a situation in which it does work, my example is one in which it does not; yours is a top-level iterator and mine is a closure iterator. Perhaps that makes a difference? My primary concern is that the behavior of I'm actually starting to wonder now if spawned functions, threads, and other asynchronous calls with |
Yes, my suggestion was to get it working. That does not mean that there is no bug it should just give you an example to work with and continue your project until the bug has been fixed.
I don't think that would be true, as my example shows a defer statement in an iterator that does not run to completion. And here everything works as it should. |
Well, I doubt we can do much about this. proc count(n: int): iterator(): int =
return iterator(): int =
try:
for i in 1..n:
yield i
finally:
echo "Defer was executed!"
let it = count(10)
for i in 1..11:
echo $it() |
Then I am tagging it as such. @massung sorry if this causes much headache to you. |
Not sure if this will technically count as a feature request, but in case this not current desired behavior I submitted it as a bug.
When using
defer
in aniterator
, it works only if the iterator runs to completion. I suppose that might be "correct", but it can make some things considerably more tricky.Consider:
It might be nice if - upon cleanup (the iterator being finalized/garbage collected or program exit) - that the
defer
still happened. Because - as is - it can make some patterns a bit tricky. Example:I would have expected
head
, when done, to close the file. But that won't happen in this case and instead just leave the file open. Yet, once I leave scope, it's impossible for the iterator to advance any more or to ever complete.I imagine this change might be quite complex given that
defer
appears to be just a macro that expands to atry
..finally
?Anyway, this was something I ran into that took me a bit to track down why some cleanup code wasn't executing. I've worked around it, but - even if the current behavior is kept (and I'd understand why) - I imagine this will be a "gotchya" for future users if not clearly stated somewhere in the documentation.
The text was updated successfully, but these errors were encountered: