Please note that in my full use case, some values will be skipped or iteration may not be in order.
var s = @[1, 2, 3, 4]
## inline iterator with mutable output
for val in s.mitems:
val *= 2
echo s #@[2, 4, 6, 8]
2. A closure iterator with immutable yield can be written like this
proc values*[T](s: seq[T]): auto {.noSideEffect.}=
return iterator(): T =
for val in s:
yield val
let it = s.values
for val in it():
echo val
3. Now this is not working (expression has no address)
proc mvalues[T](s: var seq[T]): auto {.noSideEffect.}=
return iterator(): var T =
for val in s:
yield val
var mit = s.mvalues
for old_val, val in zip(seq1.mvalues, seq2.values):
old_val = val
5. For reference this is the zip iterator that accepts 2 closure iterators
iterator zip[T1, T2](inp1: iterator(): T1, inp2: iterator(): T2): (T1, T2) {.noSideEffect.} =
## Inline iteration on 2 closure iterators at the same time
let it1 = inp1
let it2 = inp2
while true:
let val1 = it1()
let val2 = it2()
if finished(it1) or finished(it2):
break
yield (val1, val2)
Is there a way to make 4 works by modifying 3 and 5? I suspect it's not possible for a closure iterator to borrow a var seq.
I think what you are missing is mitems. (from 'system.nim')
proc mvalues[T](s: var seq[T]): auto {.noSideEffect.}=
return iterator(): var T =
for val in s.mitems:
yield val
var mit = s.mvalues
Indeed ! First mistake.
Now I have illegal capture
playground_mutiter.nim(9, 12) template/generic instantiation from here
lib/system.nim(3590, 15) Error: illegal capture 's'
var s = @[1, 2, 3, 4, 5]
proc mvalues[T](s: var seq[T]): auto {.noSideEffect.}=
return iterator(): var T =
for val in s.mitems:
yield val
var mit = s.mvalues
for i in mit():
i *= 2
As suspected, it's not possible to yield mutable values with a closure iterator as it would violate memory safety, similarly to this github issue
The only efficient alternative to my current way is if we could actually chain inline iterators: https://forum.nim-lang.org/t/2972.
Edit: Current way example
Hi mratsim,
IMO, chaining inline iterators is much butter solution as the performance is as good as manually crafted loop. Closure iterators are slower, as they usually copy on capture and they need to maintain the state
@cdome I would LOVE to chain them but as you can see in this topic I was unable to make even enumerate(it) or zip(it1, it2) work at all :/
I would switch immediately to inline iterator everywhere if someone can show me the way!