Iterator(T) - Crystal 1.3.2 mentions an Iterator working on Range#each if used without a block, does that trick similarly for any method that requires a block?
Are you asking if SomeClass.each
will always return an Iterator
if you don’t give it a block? If so, the answer is no. #each
methods that return Iterator
are specifically written for each type that implements it.
Just to follow up on this, I wanted to show a fairly typical example:
Range#each
def each
{% if B == Nil %}
{% raise "Can't each beginless range" %}
{% end %}
if @begin.nil?
raise ArgumentError.new("Can't each beginless range")
end
ItemIterator.new(self)
end
(source)
This example shows that we can’t just have a block-less #each
return an Iterator
because implementing types (almost) always require their own custom iterators. In the case of Range
, it’s ItemIterator
, which is here, if you’re interested. If you want to learn more, especially if you’re implementing your own Iterator
, I highly recommend looking through the module source to see the implementations of iterators there.
Note: all of the code and links here are for Crystal 1.3.2.
Thanks!
As a point of feedback to the core people, it seems surprising to me that this code:
(1..10_000_000).select(&.even?)
behaves far differently than the iterator version:
(1..10_000_000).each.select(&.even?)
If it were me I’d try to make it more clear somehow, to readers…maybe add the word lazy to the name?
(1..10_000_000).lazy_each.select(&.even?)
To make it clearer? Even though that’s less ruby-like. Cheers!