A Stateful iterator “empties” itself as one iterates through it. The result is the following fun behaviour (if one thinks about for a minute it becomes obvious why this happens):
using Base.Iterators: Stateful
x = [1,2,3,4]
# INTENDED BEHAVIOUR
A = [ a * b for a in x, b in x ]
# 4×4 Matrix{Int64}:
# 1 2 3 4
# 2 4 6 8
# 3 6 9 12
# 4 8 12 16
# UNINTENDED (I THINK?!)
B = [ a * b for a in Stateful(x), b in Stateful(x) ]
# 3×3 Matrix{Int64}:
# 1 4 0
# 2 0 0
# 3 0 0
I understand why this happens and it is easy enough to avoid, but I was simply curious: is this really intended? Or a bug in Stateful? or a bug in nested comprehensions?
P.S.: More generally this will of course happen to every iterator that cannot re-initialize after looping through it.
I’d argue it is a bug in nested comprehensions that [i for i in I, j in 1:2] does not throw an error if the length of I shrinks from j = 1 to j = 2. Everything else is as intended, I guess?
julia> [a * b for a in Iterators.Stateful(1:4), b in Iterators.Stateful(1:4)] # as in the OP
3×3 Matrix{Int64}:
1 4 0
2 0 0
3 0 0
julia> [a * b for a in Iterators.Stateful(1:4), b in Iterators.Stateful(1:4) if true]
4-element Vector{Int64}:
1
2
3
4
julia> [a * b for a in Iterators.Stateful(1:4) for b in Iterators.Stateful(1:4)]
16-element Vector{Int64}:
1
2
3
4
2
4
6
8
3
6
9
12
4
8
12
16
If you know the implementation, you can see that these are all leaky abstractions. Not sure what was the intention of the design, though.