# Custom iterator failed

**URL:** <https://discourse.julialang.org/t/custom-iterator-failed/103301>\
**Category:** New to Julia\
**Tags:** iterators\
**Created:** [August 28, 2023, 4:47pm UTC](https://discourse.julialang.org/t/custom-iterator-failed/103301 "2023-08-28T16:47:34Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Denis\_Ivanov](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/denis_ivanov/32/52607_2.png) [@Denis\_Ivanov](https://discourse.julialang.org/u/Denis_Ivanov)\
**Post date:** [August 28, 2023, 4:47pm UTC](https://discourse.julialang.org/t/custom-iterator-failed/103301/1 "2023-08-28T16:47:34Z")

</div>

Here is very simple idea:

```julia
struct Test
  a::Int
  n::Int
end

step(x::Int) = x > 1 ? x - 1 : 1

Base.iterate(t::Test, state=1) = 
state > t.n ? nothing : (step(t.a), state + 1)

Base.length(t::Test) = t.n

```

For

```julia
some = Test(5, 3)
foreach(p->println(p), some)

```

I suppose to get `5, 4, 3`  
but code produce ` 4, 4, 4`

---

<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:** [August 28, 2023, 5:07pm UTC](https://discourse.julialang.org/t/custom-iterator-failed/103301/2 "2023-08-28T17:07:05Z")

</div>

What result do you expect? What is the code supposed to do?

---

<div class="post-metadata">

**Author:** ![lostella](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lostella/32/356_2.png) [@lostella](https://discourse.julialang.org/u/lostella)\
**Post date:** [August 28, 2023, 5:07pm UTC](https://discourse.julialang.org/t/custom-iterator-failed/103301/3 "2023-08-28T17:07:27Z")

</div>

`t.a` is always 5 (struct is immutable) so `step` always returns 4

---

<div class="post-metadata">

**Author:** ![Denis\_Ivanov](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/denis_ivanov/32/52607_2.png) [@Denis\_Ivanov](https://discourse.julialang.org/u/Denis_Ivanov)\
**Post date:** [August 28, 2023, 5:11pm UTC](https://discourse.julialang.org/t/custom-iterator-failed/103301/4 "2023-08-28T17:11:18Z")

</div>

So I should make `mutable struct` ?

---

<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:** [August 28, 2023, 5:48pm UTC](https://discourse.julialang.org/t/custom-iterator-failed/103301/5 "2023-08-28T17:48:53Z")

</div>

Could you give a short explanation of what you would want the code in question to do? E.g. the output that you would expect.

This would make finding the issue much easier.

EDIT: I just saw you edited your post.

```julia
mutable struct Test
  a::Int
  n::Int
end

step(t::Test) = t.a > 1 ? (t.a -= 1) : 1

Base.iterate(t::Test, state=1) = 
state > t.n ? nothing : (step(t), state + 1)

Base.length(t::Test) = t.n

```

Like you suggested, T is now mutable und step now takes an argument of type Test and changes the value of t.a.

Does this work for you? (typing on the phone, so cannot check…)

---

<div class="post-metadata">

**Author:** ![lostella](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lostella/32/356_2.png) [@lostella](https://discourse.julialang.org/u/lostella)\
**Post date:** [August 28, 2023, 6:04pm UTC](https://discourse.julialang.org/t/custom-iterator-failed/103301/6 "2023-08-28T18:04:39Z")

</div>

It depends: do you want it to mutate? That is to say: do you want it to behave differently if you iterate over it twice? If so, you can make it mutable.

Otherwise, keep it immutable and let the state keep track of the iteration progress (after all, that’s what the “state” is meant to do).

I find it always better to have immutable structs, and delegate all state tracking to the iteration state (ie the second argument to `iterate`). Then one can always make the iterator stateful using `Iterators.Stateful` from `Base`, see [Iteration utilities · The Julia Language](https://docs.julialang.org/en/v1/base/iterators/#Base.Iterators.Stateful)

---

<div class="post-metadata">

**Author:** ![Denis\_Ivanov](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/denis_ivanov/32/52607_2.png) [@Denis\_Ivanov](https://discourse.julialang.org/u/Denis_Ivanov)\
**Post date:** [August 28, 2023, 6:09pm UTC](https://discourse.julialang.org/t/custom-iterator-failed/103301/7 "2023-08-28T18:09:44Z")

</div>

I saw many examples are immutable, and I prefer it!  
But would you please explain, how to change this code without `mutable`?  
In standard example from [Iteration utilities](https://docs.julialang.org/en/v1/base/iterators/#Base.Iterators.Stateful) there is no dependency from previous value

---

<div class="post-metadata">

**Author:** ![lostella](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lostella/32/356_2.png) [@lostella](https://discourse.julialang.org/u/lostella)\
**Post date:** [August 28, 2023, 6:13pm UTC](https://discourse.julialang.org/t/custom-iterator-failed/103301/8 "2023-08-28T18:13:36Z")

</div>

For example, you could structure the state as follows: initially

```julia
state = (t.a, 1)

```

Then `iterate` returns `state[1], (state[1]-1, state[2]+1)`, or `nothing` if `state[2] > t.n`.

Edit: the idea is to keep in the state both the next value we want to return, and some other value that helps us decide when we need to stop.

---

<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:** [August 28, 2023, 6:15pm UTC](https://discourse.julialang.org/t/custom-iterator-failed/103301/9 "2023-08-28T18:15:44Z")

</div>

An equivalent solution, that does not modify t could work along the lines of:

```julia
struct Test
  a::Int
  n::Int
end

step(x::Int, state) = x - state > 1 ? x - state : 1

Base.iterate(t::Test, state=1) = 
state > t.n ? nothing : (step(t.a,state), state + 1)

Base.length(t::Test) = t.n

```

---

<div class="post-metadata">

**Author:** ![Denis\_Ivanov](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/denis_ivanov/32/52607_2.png) [@Denis\_Ivanov](https://discourse.julialang.org/u/Denis_Ivanov)\
**Post date:** [August 28, 2023, 6:18pm UTC](https://discourse.julialang.org/t/custom-iterator-failed/103301/10 "2023-08-28T18:18:46Z")

</div>

No, no! I gave a simple example, working on a more complex design.  
The next value depends _only on the previous_, does not depend on `state`!

---

<div class="post-metadata">

**Author:** ![lostella](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lostella/32/356_2.png) [@lostella](https://discourse.julialang.org/u/lostella)\
**Post date:** [August 28, 2023, 6:40pm UTC](https://discourse.julialang.org/t/custom-iterator-failed/103301/11 "2023-08-28T18:40:21Z")

</div>

Well, `iterate` does not get the previous value as input, but only the state. So the only way to achieve that, with an immutable iterator, is to store in the state everything you need to compute the next value. (This is true always, not just in this example)

---

<div class="post-metadata">

**Author:** ![Denis\_Ivanov](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/denis_ivanov/32/52607_2.png) [@Denis\_Ivanov](https://discourse.julialang.org/u/Denis_Ivanov)\
**Post date:** [August 28, 2023, 6:41pm UTC](https://discourse.julialang.org/t/custom-iterator-failed/103301/12 "2023-08-28T18:41:02Z")

</div>

Well, looks like i do it

---

<div class="post-metadata">

**Author:** ![Denis\_Ivanov](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/denis_ivanov/32/52607_2.png) [@Denis\_Ivanov](https://discourse.julialang.org/u/Denis_Ivanov)\
**Post date:** [August 28, 2023, 6:41pm UTC](https://discourse.julialang.org/t/custom-iterator-failed/103301/13 "2023-08-28T18:41:41Z")

</div>

```julia
struct Test
  a::Int
  n::Int
end

step(x::Int) = x > 1 ? x - 1 : 1

function Base.iterate(t::Test)
  return (t.a, (t.a, 1))
end

function Base.iterate(t::Test, state) 
  next = step(state[1])
  state[2] >= t.n ? nothing : (next, (next, state[2] + 1))
end

Base.length(t::Test) = t.n

z = Test(5, 3)
for p in z
  println(p)
end

```

`5, 4, 3`
