# Explain generators

**URL:** <https://discourse.julialang.org/t/explain-generators/109573>\
**Category:** New to Julia\
**Tags:** question, generator\
**Created:** [February 1, 2024, 1:57pm UTC](https://discourse.julialang.org/t/explain-generators/109573 "2024-02-01T13:57:04Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Anders\_Holtsberg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/anders_holtsberg/32/206165_2.png) [@Anders\_Holtsberg](https://discourse.julialang.org/u/Anders_Holtsberg)\
**Post date:** [February 1, 2024, 1:57pm UTC](https://discourse.julialang.org/t/explain-generators/109573/1 "2024-02-01T13:57:04Z")

</div>

I am trying to understand how to implement a simple generator so that I can traverse my graphs in different ways. It boils down to the example below. In Lua - which I come from - it works without any ado, but in Julia it has to be written as, well into what?

I saw there is a type Channel, is that the way to go?  
Or @yield or @task?  
Or is best practice to rewrite it as Base.iterator?  
Or Base.start/next/done instead of syntactic scoping?

So, what simple best practice here?

Sorry, but I am a newbie here and when I google generators I get a gazillion hits on prebuilt generators but not what I want. I want a for loop to simply run my generator.

```julia
x = [1,3,2,4,9,8,7,6,5]

function godd(x)
   k = 1
   return function()
      while k <= length(x)
         v = x[k]
         k += 1
         if v % 2 == 1
            return k - 1, v
         end 
      end
      return nothing
   end
end

for (k, v) in godd(x)
   println(k, "\t", v)
end

```

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [February 1, 2024, 2:05pm UTC](https://discourse.julialang.org/t/explain-generators/109573/2 "2024-02-01T14:05:40Z")

</div>

The for loop will try to use the iteration interface.

[https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-iteration](https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-iteration)

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [February 1, 2024, 2:24pm UTC](https://discourse.julialang.org/t/explain-generators/109573/3 "2024-02-01T14:24:38Z")

</div>

The way I would write this idiomatically is as follows.

```julia-repl
julia> f = Iterators.filter(pairs(x)) do (k,v)
           v % 2 == 1
       end;

julia> for (k,v) in f
           println(k, "\t", v)
       end
1 1
2 3
5 9
7 7
9 5

```

A more direct implementation with some similarities to your original code would be as follows.

```julia-repl
julia> struct Foo{V}
           x::V
       end

julia> function Base.iterate(f::Foo, k = 1)
             while k <= length(f.x)
                v = f.x[k]
                k += 1
                if v % 2 == 1
                   return k - 1 => v, k
                end
             end
             return nothing
       end

julia> f = Foo(x)
Foo{Vector{Int64}}([1, 3, 2, 4, 9, 8, 7, 6, 5])

julia> for (k,v) in f
           println(k, "\t", v)
       end
1 1
2 3
5 9
7 7
9 5

```

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [February 1, 2024, 2:25pm UTC](https://discourse.julialang.org/t/explain-generators/109573/4 "2024-02-01T14:25:11Z")

</div>

> [@Anders\_Holtsberg](#):
>
> So, what simple best practice here?

As you saw, there are many options, differing mainly in terms of the performance they offer vs the difficulty of development.

Could you tell us more about your use case? Is there a performance requirement for the iterator itself?

---

<div class="post-metadata">

**Author:** ![Anders\_Holtsberg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/anders_holtsberg/32/206165_2.png) [@Anders\_Holtsberg](https://discourse.julialang.org/u/Anders_Holtsberg)\
**Post date:** [February 1, 2024, 2:36pm UTC](https://discourse.julialang.org/t/explain-generators/109573/5 "2024-02-01T14:36:02Z")

</div>

No performance. Maximum simplicity. Think about a Directed Acyclic Word Graph or som other complicated monster. There are several ways to print it out or mangle it.

But I thought about it as a convenience for a user of the module to use and print stuff (both for testing and production).

```julia
for node in all_unique_nodes(mymonster)
    print(node)
end

for leaf in all_leaves(mymonster)
    print(leaf)
end

for string in wordstrings(mymonster)
    print(string)
end

```

EDIT: Or what a good way to traverse a tree? I was thinking of something like this

```julia
for node in mytraverse(mytree, option="depthfirst")
    treat(node)
end

```

---

<div class="post-metadata">

**Author:** ![Anders\_Holtsberg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/anders_holtsberg/32/206165_2.png) [@Anders\_Holtsberg](https://discourse.julialang.org/u/Anders_Holtsberg)\
**Post date:** [February 1, 2024, 2:46pm UTC](https://discourse.julialang.org/t/explain-generators/109573/6 "2024-02-01T14:46:25Z")

</div>

Thanks. Yes. That demands a type, but that is my case and this is this I will use.

EDIT: Well, that version still doesn’t solve if I want to have two views of the same data type:

```julia
for n in nodes(X) ...
for s in strings(X) ...

```

EDIT2: or maybe it does if I introduce two different artificial types … OK I am on track and will solve it.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [February 1, 2024, 6:20pm UTC](https://discourse.julialang.org/t/explain-generators/109573/7 "2024-02-01T18:20:32Z")

</div>

I’m not sure what your later questions are getting at, but as for the original one, there is also just regular simple generators, which you get from using `( ... )` syntax:

```julia
julia> mygen(x) = ((k, v) for (k, v) in pairs(x) if isodd(v))

julia> for (k, v) in mygen(x)
           println(k, '\t', v)
       end
1 1
2 3
5 9
7 7
9 5

```

There’s also an `iseven` function, btw.

---

<div class="post-metadata">

**Author:** ![Anders\_Holtsberg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/anders_holtsberg/32/206165_2.png) [@Anders\_Holtsberg](https://discourse.julialang.org/u/Anders_Holtsberg)\
**Post date:** [February 1, 2024, 6:45pm UTC](https://discourse.julialang.org/t/explain-generators/109573/8 "2024-02-01T18:45:34Z")

</div>

I am more interested in the case where x is really opaque. A monster struct. Let’s take another example. We have a doubly linked list. Then one could traverse it. Or traverse it backwards.

```julia
for elem in doublylinkedlist ...
for elem in backwards(doublylinkedlist) ... 

```

I am more interested in the clean options for doing stuff like that on opaque things. Or learn that that’s not the way to think in Julia.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [February 1, 2024, 7:03pm UTC](https://discourse.julialang.org/t/explain-generators/109573/9 "2024-02-01T19:03:01Z")

</div>

Ok, I was mainly addressing the original question, and since it was about generators, I found Base.Generator to be relevant.

---

<div class="post-metadata">

**Author:** ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)\
**Post date:** [February 1, 2024, 9:46pm UTC](https://discourse.julialang.org/t/explain-generators/109573/10 "2024-02-01T21:46:29Z")

</div>

[here](https://julialang.org/blog/2018/07/iterators-in-julia-0.7/) some element of “theory” on the subject.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [February 1, 2024, 10:08pm UTC](https://discourse.julialang.org/t/explain-generators/109573/11 "2024-02-01T22:08:17Z")

</div>

Julia has a generator syntax that works as follows.

```julia
julia> f(x) = x^2
f (generic function with 1 method)

julia> gen = (f(x) for x in 1:5)
Base.Generator{UnitRange{Int64}, var"#1#2"}(var"#1#2"(), 1:5)

julia> for y in gen
           println(y)
       end
1
4
9
16
25

```

We can apply it to the original problem by adding a conditional statement.

```julia
julia> x = [1,3,2,4,9,8,7,6,5];

julia> gen = (k => v for (k,v) in pairs(x) if v % 2 == 1)
Base.Generator{Base.Iterators.Filter{var"#4#6", Base.Pairs{Int64, Int64, LinearIndices{1, Tuple{Base.OneTo{Int64}}}, Vector{Int64}}}, var"#3#5"}(var"#3#5"(), Base.Iterators.Filter{var"#4#6", Base.Pairs{Int64, Int64, LinearIndices{1, Tuple{Base.OneTo{Int64}}}, Vector{Int64}}}(var"#4#6"(), Base.Pairs(1 => 1, 2 => 3, 3 => 2, 4 => 4, 5 => 9, 6 => 8, 7 => 7, 8 => 6, 9 => 5)))

julia> for (k,v) in gen
           println(k, "\t", v)
       end
1	1
2	3
5	9
7	7
9	5

```

Essentially what we are doing is wrapping our desired function in a `Base.Generator`. Note that in general, Julia iterators are usually stateless. That is we can iterate through the generator multiple times.

```julia
julia> for (k,v) in gen
           println(k, "\t", v)
       end
1	1
2	3
5	9
7	7
9	5

julia> for (k,v) in gen
           println(k, "\t", v)
       end
1	1
2	3
5	9
7	7
9	5

julia> for (k,v) in gen
           println(k, "\t", v)
       end
1	1
2	3
5	9
7	7
9	5

julia> for (k,v) in gen
           println(k, "\t", v)
       end
1	1
2	3
5	9
7	7
9	5

```

Something helpful to you might be an adaptor from Lua to Julia.

```julia
julia> struct LuaGenerator{F}
           f::F
       end

julia> function Base.iterate(lg::LuaGenerator, _=nothing)
           r = lg.f()
           isnothing(r) ? nothing : (r, nothing)
       end

julia> for (k,v) in LuaGenerator(godd(x))
           println(k, "\t", v)
       end
1	1
2	3
5	9
7	7
9	5

julia> for (k,v) in LuaGenerator(godd(x))
           println(k, "\t", v)
       end
1	1
2	3
5	9
7	7
9	5

julia> gen = LuaGenerator(godd(x))
LuaGenerator{var"#7#8"{Vector{Int64}}}(var"#7#8"{Vector{Int64}}([1, 3, 2, 4, 9, 8, 7, 6, 5], Core.Box(1)))

julia> for (k,v) in gen
           println(k, "\t", v)
       end
1	1
2	3
5	9
7	7
9	5

julia> for (k,v) in gen # this generator is stateful
           println(k, "\t", v)
       end

```

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [February 2, 2024, 5:03am UTC](https://discourse.julialang.org/t/explain-generators/109573/12 "2024-02-02T05:03:45Z")

</div>

One last thought. The `function` returned from `godd(x)` has a specific type itself. Thus, we can just define `iterate` directly for the function type.

```julia-repl
julia> function Base.iterate(func::typeof(godd(x)), _=nothing)
           r = func()
           isnothing(r) ? nothing : (r, nothing)
       end

julia> for (k,v) in godd(x)
           println(k, "\t", v)
       end
1	1
2	3
5	9
7	7
9	5

```

An alternative way to define `iterate` would be to use `Base.return_types`.

```julia-repl
julia> function Base.iterate(func::only(Base.return_types(godd)), _=nothing)
           r = func()
           isnothing(r) ? nothing : (r, nothing)
       end

```
