How is Array # each implemented in Ruby?

I'm interested in the collection and locking mechanism in Ruby. We can define a class like this:

class Foo
    include Enumerable
    def initialize
        @data = []
    end

    def each
        if block_given?
            @data.each { |e| yield(e) }
        else
            Enumerator.new(self, :each)
        end
    end 
end

      

I want to know how a @data.each

block can be used { |e| yield(e) }

as a parameter. I was looking for an implementation of the # each array:

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

    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
    for (i=0; i<RARRAY_LEN(ary); i++) {
        rb_yield(RARRAY_AREF(ary, i));
    }
    return ary;
}

      

but that doesn't even look like a Ruby language implementation. How is it implemented Array#each

in Ruby?

Edit:

It looks like the C code traverses the first and last elements of the array and calls the ruby ​​return function with the array element parameter of the traversed array. But where is the block passed to the function rb_ary_each

?

+3


source to share


2 answers


Here is a simple Ruby implementation of a method each

that doesn't rely on the existence of any of Ruby's built-in iterator methods:

class List
  def initialize(arr)
    @arr = arr
  end
  def each
    i = 0
    while i < @arr.length
      yield @arr[i]
      i += 1
    end
  end
end

      

Using:



l = List.new(['a', 'b', 'c'])
l.each {|x| puts x}

      

Output:

a
b
c

      

0


source


I may be late on this topic, but my guess is that the VALUE array is an object / structure instead of a primitive value like int, char, etc. So which method rb_ary_each gets a pointer / reference to an object / struct of type VALUE. If this is true (I'm just guessing I know about C) then the block is passed inside the object / structure with the rest of the arguments.

I also assume that another object / structure must exist to store the / proc / lambda block, so the VALUE object / structure must contain a pointer / reference to the first one.



If I am wrong, please someone will correct me! Your question has a lot more to do with how C works than Ruby.

0


source







All Articles