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
?
source to share
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
source to share
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.
source to share