3

I have been learning ruby and interested in knowing how 'each' is implemented in the array class. I saw one documentation here and it looks like this is how 'each' is written;

# within class Array...
def each
  for each element
    yield(element)
  end
end

I did exactly write the code above (without the comment#) in the ruby console (I'm using 1.9.2) and got this syntax error

:SyntaxError: (irb):2: syntax error, unexpected tIDENTIFIER, expecting keyword_do or '{' or '('
(irb):5: syntax error, unexpected keyword_end, expecting $end

Is this happening due to incomplete array class implementation (i.e 'element' is not defined or is this because of anything else? I'd also like to know how 'each' and other basic fnctions are implemented. Any reference to the right documentation/answers would be helpful. Let me know if this is a duplicate (i didnt see any similar questions). thanks

Benny Tjia
  • 4,853
  • 10
  • 39
  • 48

4 Answers4

12

You can do this (don't miss the in):

class Array
  def each
    for element in self
      yield element
    end
  end
end

But the fact is:

for element in array is syntax sugar of array.each

So the above code is transformed into this:

class Array
  def each
    each do |element|
      yield element
    end
  end
end

And you stackoverflow.

luikore
  • 750
  • 5
  • 16
7

First off, the syntax of your for statement is off, it should be something like for element in elements, which is almost equivalent to elements.each { |element| ... } except that it doesn't introduce a new scope. In fact for is implemented using each, as can be seen when you try to call it on a method that has no defined each method:

>> for element in nil
..   end
NoMethodError: undefined method `each' for nil:NilClass
    from (irb):1

Regarding your syntax error: since you are reopening a class, when the Ruby parser sees the standalone each it uses self as the receiver, so it translates your statement to for self.each element, where element is the tIDENTIFIER mentioned, whereas something like self.each do |element| ... end would have been expected.

As for the implementation of Array#each, it's implemented in C and looks like this

VALUE
rb_ary_each(VALUE array)
{
    long i;
    volatile VALUE ary = array;

    RETURN_ENUMERATOR(ary, 0, 0);
    for (i=0; i<RARRAY_LEN(ary); i++) {
        rb_yield(RARRAY_PTR(ary)[i]);
    }
    return ary;
}

This is basically what you tried to write in Ruby in C.

Michael Kohl
  • 66,324
  • 14
  • 138
  • 158
0

It is possible by looping over range from 0 to size of array (excluded)

class Array
  def each
    for i in 0...self.size
      yield self[i]
    end
  end
end

Example:

[1,2,3].each {|i| puts i}
1
2
3

It works!

denis.peplin
  • 9,585
  • 3
  • 48
  • 55
0

Array#each is built in method with Ruby. It is not patched in any gem. See the documentation here

Sayuj
  • 7,464
  • 13
  • 59
  • 76