# Automatic iterators!

**URL:** <https://forum.crystal-lang.org/t/automatic-iterators/2001>\
**Category:** Offtopic\
**Created:** [April 25, 2020, 11:45am UTC](https://forum.crystal-lang.org/t/automatic-iterators/2001 "2020-04-25T11:45:18Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![j8r](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/j8r/32/111_2.png) [@j8r](https://forum.crystal-lang.org/u/j8r)\
**Post date:** [April 25, 2020, 11:45am UTC](https://forum.crystal-lang.org/t/automatic-iterators/2001/1 "2020-04-25T11:45:18Z")

</div>

…and there is a catch 😉

The implementation is event-driven, in order to continue the enumerator loop as will, each time `next` is called.

```crystal
class AutoIterator(T)
  include Iterator(T)

  class Stop < Exception
  end

  @value_channel = Channel(T | Iterator::Stop).new
  @next_channel = Channel(Nil).new
  @proc : Proc(Proc(T, Nil), Nil)
  @first = true
  @end : Iterator::Stop | Nil = nil

  private def initialize(@proc)
  end

  def self.new(&proc : Proc(T, Nil) ->)
    new proc
  end
  
  private def sender(value : T)
    @value_channel.send value
    @next_channel.receive?
    raise Stop.new if @end
  end

  def next : T | Iterator::Stop
    if end_result = @end
      return end_result
    elsif @first
      spawn do
        @proc.call ->sender(T)
        @value_channel.send(Iterator::Stop::INSTANCE) if !@end
      rescue ex : Stop
      end
      @first = false
    else
      @next_channel.send nil
    end
    result = @value_channel.receive
    if result.is_a? Iterator::Stop
      close
    end
    result
  end
  
  def close
    @value_channel.close
    @next_channel.close
    @end = Iterator::Stop::INSTANCE
  end
end

i = AutoIterator(Char).new do |sender|
  "ab".each_char do |char|
    sender.call char
  end
end
puts "Starting"
puts i.next #=> a

puts "Do some other stuff"
puts i.next #=> b

puts "The end"
puts i.next #=> Iterator::Stop

```

Obviously, this iterator is slower than the custom `String::CharIterator` returned by `String#each_char` (benchmarks shows 4x slower), but it is still useful in some cases.  
When making a custom iterator is not worth the effort, especially when each iteration is expensive, `AutoIterator` may be a good option.

Beware it is more a POC than anything else, there are flaws. It’s there because it is possible 😁

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [April 25, 2020, 1:39pm UTC](https://forum.crystal-lang.org/t/automatic-iterators/2001/2 "2020-04-25T13:39:08Z")

</div>

IIUC this would implement [https://github.com/crystal-lang/crystal/issues/6357](https://github.com/crystal-lang/crystal/issues/6357) ?

---

<div class="post-metadata">

**Author:** ![rogerdpack](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/rogerdpack/32/117_2.png) [@rogerdpack](https://forum.crystal-lang.org/u/rogerdpack)\
**Post date:** [April 26, 2020, 1:54am UTC](https://forum.crystal-lang.org/t/automatic-iterators/2001/3 "2020-04-26T01:54:00Z")

</div>

What’s the use case, more background?

---

<div class="post-metadata">

**Author:** ![jhass](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/jhass/32/1779_2.png) [@jhass](https://forum.crystal-lang.org/u/jhass)\
**Post date:** [April 26, 2020, 8:57am UTC](https://forum.crystal-lang.org/t/automatic-iterators/2001/4 "2020-04-26T08:57:15Z")

</div>

Ah, that brings back memories. I had something like this before we even had any `Iterator` :D

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [April 26, 2020, 11:14am UTC](https://forum.crystal-lang.org/t/automatic-iterators/2001/5 "2020-04-26T11:14:19Z")

</div>

Collection types currently have to provide two different implementations for iterating the items if you wont both a yielding method and an iterator: `each(& : T ->)` and `each : Iterator(T)` are completely separate. And the latter is usually more complex because it needs an extra iterator type to keep track of state.  
If we had a reliable way to base an `Iterator(T)` on a method that yields `T`, it would be a huge improvement.  
Currently, most standard collection types have both implementations. But many (especially outside of stdlib) don’t implement the iterator because it’s more work.

---

<div class="post-metadata">

**Author:** ![waj](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/waj/32/223_2.png) [@waj](https://forum.crystal-lang.org/u/waj)\
**Post date:** [April 27, 2020, 1:23am UTC](https://forum.crystal-lang.org/t/automatic-iterators/2001/6 "2020-04-27T01:23:11Z")

</div>

It would be possible to autogenerate iterators from code that `yield` values. Of course, not any code with `yield` is convertible to an iterator, but with some restrictions it might happen someday. Maybe before Crystal 2.0, who knows 😁
