# Unpacking CartesianIndex

``````for (i, j) in CartesianIndices(a)
println(i, j)
end
``````

produces an error:

``````ERROR: iteration is deliberately unsupported for CartesianIndex. Use `I` rather than `I...`, or use `Tuple(I)...`
``````

This is an unreasonable design of the Julia interface in my opinion, which implements unpacking using iterator. I suggest Julia have an additional function `unpack` which is called when unpacking syntax is used and only falls back to `iterate` by default.

1 Like

Take this:

``````for (i, j) in Tuple.(CartesianIndices(a))
println(i, j)
end
``````
2 Likes

While the wording of this suggestion is rather forceful, there is merit to it, I think.

1 Like

It was using `map` to get around this. Thanks

Note that this (and equivalent `map` version) are allocating because they materialize a vector of tuples.

Compare with a non-allocating alternative (`unpack2` below) which runs about 7x faster on my machine.

``````function unpack1(dims)
s = 0
for (i, j) in Tuple.(CartesianIndices(dims))
#println(i, j)
s += i + j
end
return s
end

function unpack2(dims)
s = 0
for ci in CartesianIndices(dims)
i, j = Tuple(ci)
#println(i, j)
s += i + j
end
return s
end
``````
``````using BenchmarkTools
const dims = (1000, 1000)
@btime unpack1(\$dims)
@btime unpack2(\$dims)
``````

Apparently, iteration of a `CartesianIndex` is disabled to avoid a possible performance trap when splatting a `CartesianIndex`. See #23719

If you want to live dangerously, you could define iteration on `CartesianIndex` yourself.
This version (`unpack3` below) is also non-allocating, and is also ~7x faster than the â€śmaterializingâ€ť version.

``````Base.iterate(ci::CartesianIndex) = iterate(Tuple(ci))
Base.iterate(ci::CartesianIndex, state) = iterate(Tuple(ci), state)

function unpack3(dims)
s = 0
for (i, j) in CartesianIndices(dims)
#println(i, j)
s += i + j
end
return s
end
``````

In this case, a generator expression also works well (although in general generators sometimes are way slower due to type-problems), see:

``````julia> function unpack4(dims)
s = 0
for (i,j) in (Tuple(c) for c in CartesianIndices(dims))
s += i + j
end
return s
end
``````

which on my system is as fast as `unpack2`.

1 Like

I thought `map` returns a generator, which is how python works. It turns out to return a vector.

Depending on the situation, eager operations is usually more efficient that lazy ones if everything fits into the memory. Iâ€™m not sure why in this case it is slower.