# Iterate on calculated iterable

**URL:** https://discourse.julialang.org/t/iterate-on-calculated-iterable/132026
**Category:** General Usage
**Tags:** question, iterators
**Created:** [September 1, 2025, 4:32pm UTC](https://discourse.julialang.org/t/iterate-on-calculated-iterable/132026 "2025-09-01T16:32:55Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [September 1, 2025, 4:32pm UTC](https://discourse.julialang.org/t/iterate-on-calculated-iterable/132026/1 "2025-09-01T16:32:55Z")

</div>

I have a type for which I want to implement a kind of iteration, which I can easily do with functions in `Iterators`. But I want iteration to happen on something I construct. MWE:

```julia
struct NamedProduct{T}
    np::T
end

function make_iterable(itr::NamedProduct{<:NamedTuple{N}}) where N
    Iterators.map(NamedTuple{N}, Iterators.product(values(itr.np)...))
end

I = NamedProduct((a = 1:4, b = 2:3))
collect(make_iterable(I))
collect(I) # <= I want this to be equivalent

```

So one horrible, horrible solution I came up with is hiding the resulting iterator in the state, like this:

```julia
Base.IteratorSize(itr::NamedProduct) = Base.HasShape{length(itr.np)}()

# assuming inner iterators are flat, for simpler code
Base.axes(itr::NamedProduct) = map(itr -> axes(itr, 1), values(itr.np))

function Base.iterate(itr::NamedProduct)
    inner_itr = make_iterable(itr)
    r = iterate(inner_itr)
    r ≡ nothing && return r
    elt, inner_state = r
    elt, (inner_itr, inner_state)
end

# these two functions could be combined into one,
# here they are two for clarity
function Base.iterate(itr::NamedProduct, (inner_itr, inner_state))
    r = iterate(inner_itr, inner_state)
    r ≡ nothing && return r
    elt, inner_state = r
    elt, (inner_itr, inner_state)
end

```

I am wondering if there is a package that implements a wrapper that does this, so I would not reinvent the wheel, just use that and keep my code simpler.

Also, if there is a better (nicer? more elegant?) way of doing it.

---

<div class="post-metadata">

### Author: ![\_bernhard](https://avatars.discourse-cdn.com/v4/letter/_/bc79bd/32.png) [@\_bernhard](https://discourse.julialang.org/u/_bernhard)
#### Post date: [September 1, 2025, 11:43pm UTC](https://discourse.julialang.org/t/iterate-on-calculated-iterable/132026/2 "2025-09-01T23:43:39Z")

</div>

Although you probably already thought of this, trivially you could do

```julia-auto
Base.iterate(n::NamedProduct, s...) = iterate(make_iterable(n), s...)

```

However, this reconstructs the wrapped iterator for every iteration, which might or might not be acceptable.

* * *

Also you could add an additional field to `NamedProduct` that holds the iterator and handle construction transparently in the constructor.

* * *

I would also consider a small variation of your approach that partly avoids explicit state management (and is a little less horrible).

```julia-auto
forward_itr(_, ::Nothing, ) = nothing
forward_itr(inner_itr, (el, state)) = el, (inner_itr, state)

function Base.iterate(itr::NamedProduct)
    inner_itr = make_iterable(itr)
    return forward_itr(inner_itr, iterate(inner_itr))
end

function Base.iterate(itr::NamedProduct, (inner_itr, inner_state))
    return forward_itr(inner_itr, iterate(inner_itr, inner_state))
end

```

Unfortunately, I can’t think of a package that does something like this.

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [September 2, 2025, 7:21am UTC](https://discourse.julialang.org/t/iterate-on-calculated-iterable/132026/3 "2025-09-02T07:21:38Z")

</div>

> [@\_bernhard](#):
>
> a small variation of your approach that partly avoids explicit state management (and is a little less horrible)

Thanks, I find it rather neat and it makes the code much more readable!

I am thinking about a PR to IterTools.jl, but I am wondering how this could be packaged best. Probably a macro with the syntax

```julia
@forward_iterator itr::NamedProduct make_iterable(itr)

```

which then uses the (not necessarily exposed) `forward_itr` methods.

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [September 2, 2025, 8:04am UTC](https://discourse.julialang.org/t/iterate-on-calculated-iterable/132026/4 "2025-09-02T08:04:00Z")

</div>

> [@\_bernhard](#):
>
> Also you could add an additional field to `NamedProduct` that holds the iterator and handle construction transparently in the constructor.

This may be necessary, if one wants to handle the various iterator traits by forwarding transparently.

---

<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: [September 2, 2025, 4:59pm UTC](https://discourse.julialang.org/t/iterate-on-calculated-iterable/132026/5 "2025-09-02T16:59:49Z")

</div>

Something like works fairly well:

```julia-auto
struct NamedProduct{T,I}
    np::T
    itr::I
    function NamedProduct(np::NamedTuple{N}) where N
        itr = Iterators.map(NamedTuple{N}, Iterators.product(values(np)...))
        new{typeof(np), typeof(itr)}(np, itr)
    end
end

Base.show(io::IO, I::NamedProduct) = show(io, I.np)

Base.IteratorSize(itr::NamedProduct) = Base.HasShape{length(itr.np)}()
Base.axes(itr::NamedProduct) = map(itr -> axes(itr, 1), values(itr.np))

Base.iterate(itr::NamedProduct, state...) = iterate(itr.itr, state...)

I = NamedProduct((a = 1:4, b = 2:3))
collect(I)

```

If making a general thing with a macro as indicated, it’s perhaps better to make a named tuple containing the original `NamedProduct` struct and the `itr` as separate fields, with a unique field name, so you can dispatch on it. I suppose you need some extra information for the `IteratorSize` and `axes` for a completely general macro.

---

<div class="post-metadata">

### Author: ![\_bernhard](https://avatars.discourse-cdn.com/v4/letter/_/bc79bd/32.png) [@\_bernhard](https://discourse.julialang.org/u/_bernhard)
#### Post date: [September 2, 2025, 7:24pm UTC](https://discourse.julialang.org/t/iterate-on-calculated-iterable/132026/6 "2025-09-02T19:24:37Z")

</div>

Yes, this precisely captures my suggestion 2 from above.  
It should also work to just forward the calls to `Base.IteratorSize` and `Base.axes` to the `itr` field.  
This would also make implementing a general macro far easier - simply require the created iterator type to implement the iterator interface.

This approach certainly shines due to its simplicity.  
However, it also requires to change the `struct` layout and introduces an additional type parameter.

What makes my final approach above in my opinion so appealing, is that there is no need to modify `NamedProduct`.  
It basically provides a template to plug in an arbitrarily transformed version of an object for iteration, without touching the rest of the code.

---

<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: [September 2, 2025, 10:23pm UTC](https://discourse.julialang.org/t/iterate-on-calculated-iterable/132026/7 "2025-09-02T22:23:08Z")

</div>

I agree that modifying `NamedProduct` can be messy. It’s not too difficult to use MacroTools.jl to parse the struct definition to add another parameter and a field, but it can get messy with constructors and traits.

I.e. something along the suggestion above, but at the struct definition level:

```julia-auto
@forward_iterator struct NamedProduct{T} np::T end makeiter

```

should ideally rewrite it to

```julia-auto
struct NamedProduct{T, I}
    np::T
    itr::I
    function NamedProduct(np::T) where T # this signature depends on ... uh ... the original struct
        it = makeiter(np)
        new{T, typeof(it)}(np, it)
    end
end
Base.iterate(np::NamedProduct, state...) = iterate(np.itr, state...)

```

The modified struct could be made a subtype of some `AbstractForwardIter` which has the `iterate` function.
