# Cartesian For Loop

**URL:** <https://discourse.julialang.org/t/cartesian-for-loop/130353>\
**Category:** General Usage\
**Tags:** question\
**Created:** [June 30, 2025, 11:47pm UTC](https://discourse.julialang.org/t/cartesian-for-loop/130353 "2025-06-30T23:47:39Z")\
**Posts on this page:** 4\
**Page:** 2

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [July 29, 2025, 11:25am UTC](https://discourse.julialang.org/t/cartesian-for-loop/130353/21 "2025-07-29T11:25:42Z")

</div>

Well, it’s possible to write an iterator which is updated. A stateful iterator.

```julia-auto
julia> iter1 = 1:3
1:3

julia> iter2 = Iterators.Stateful(1:3)
Base.Iterators.Stateful{UnitRange{Int64}, Union{Nothing, Tuple{Int64, Int64}}}(1:3, (1, 1))

julia> for i in iter1
           println(i)
       end
1
2
3
# and again:
julia> for i in iter1
           println(i)
       end
1
2
3

# then the stateful iter2:
julia> for i in iter2
           println(i)
       end
1
2
3
# but now it's empty:
julia> for i in iter2
           println(i)
       end

julia> 

```

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [July 29, 2025, 11:32am UTC](https://discourse.julialang.org/t/cartesian-for-loop/130353/22 "2025-07-29T11:32:56Z")

</div>

> [@WalterMadelim](#):
>
> Since the head line of `let` is essentially a `local` declaration

Semantically they make local variables, but it’s just not the same syntax, and we do different things with them. `local` doesn’t necessarily have an assignment, but when it does, it works a lot like plain assignments, including destructuring:

```julia-auto
julia> let
       local x, y = 1:2
        x, y
       end
(1, 2)

julia> let
       local (;x, y) = (y=2, x=1)
        x, y
       end
(1, 2)

```

`let` headers don’t do that

```julia-auto
julia> let x, y = 1:2
        x, y
       end
ERROR: UndefVarError: `x` not defined in local scope

```

unless you do something like argument destructuring in method definitions, which is what `let` blocks are mimicking.

```julia-auto
julia> let (x, y) = 1:2
        x, y
       end
(1, 2)

```

It could potentially have been more consistent, but that would also disallow many conveniences in plain assignments.

> [@sgaure](#):
>
> I think updating a `Dict` while you iterate over it is undefined.

I _think_ it’s fine to modify an existing element, the problem is insertion/deletion changing the indices or set of keys.

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [July 29, 2025, 12:11pm UTC](https://discourse.julialang.org/t/cartesian-for-loop/130353/23 "2025-07-29T12:11:17Z")

</div>

> [@WalterMadelim](#):
>
> The output sequence is a **complete** range, therefore I know that `for i = shuffle(1:9)` was evaluated **only once and then settled.**.

It’s actually not written in the docs (I think) that the `shuffle(1:9)` is only evaluated once. Or, it is only inferred, since what comes after `=` should be an iterator, and `shuffle(1:9)` is a call, not an iterator. This is different from e.g. a `while` loop, where the condition is evaluated every time.

When in doubt, it is possible to look at what happens lower down, e.g. with:

```julia-auto
julia> f(n) = for i in g(n); println(i); end
f (generic function with 1 method)

julia> @code_typed f(10)
CodeInfo(
1 ─ %1 = Main.g::Any
│ %2 = (%1)(n)::Any
│ %3 = Base.iterate(%2)::Any
│ %4 = (%3 === nothing)::Bool
│ %5 = Base.not_int(%4)::Bool
└── goto #4 if not %5
2 ┄ %7 = φ (#1 => %3, #3 => %11)::Any
│ %8 = Core.getfield(%7, 1)::Any
│ %9 = Core.getfield(%7, 2)::Any
│ Main.println(%8)::Any
│ %11 = Base.iterate(%2, %9)::Any
│ %12 = (%11 === nothing)::Bool
│ %13 = Base.not_int(%12)::Bool
└── goto #4 if not %13
3 ─ goto #2
4 ┄ return nothing
) => Nothing

```

Recalling that `for` loops are rewritten as `while` loops as described in [Interfaces · The Julia Language](https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-iteration), it’s possible to see that `g` is called only once (`%2 = (%1)(n)`), in section `#1` before the loop starts in section `#2`.

(The `φ`-node at the start of section `#2` (`%7 = φ ...`), means that variable `%7` is set to `%3` if section `#2` was reached from section `#1`, but to `%11` if it was reached from section `#3`. This weird intermediate format is SSA (Static Single Assignment), easy for the compiler, not for normal people)

```julia-auto

```

---

<div class="post-metadata">

**Author:** ![eldee](https://avatars.discourse-cdn.com/v4/letter/e/b5a626/32.png) [@eldee](https://discourse.julialang.org/u/eldee)\
**Post date:** [July 29, 2025, 12:55pm UTC](https://discourse.julialang.org/t/cartesian-for-loop/130353/24 "2025-07-29T12:55:34Z")

</div>

> [@sgaure](#):
>
> since what comes after `=` should be an iterator, and `shuffle(1:9)` is a call, not an iterator.

Well, the result of the `shuffle` call, i.e. the `Vector{Int}` `shuffle(1:9)` is an iterator, as it supports `iterate` 🙂

[Previous page](https://discourse.julialang.org/t/cartesian-for-loop/130353.md?page=1)
