Enumberable fails for class Subclass < Array; def enum...

L

Laza

Array includes Enumerable. But when a subclass of Array redefines
each(), then Enumerable still refers to the original Array.each(). Why
is that?
For example:

class RangeUnion < Array
def each
super{|x| x.each{|i| yield i} }
end
end

# u = RangeUnion[1..3, 11..13, "a".."c"]
# u.each{|x| print "#{x} "} # THIS WORKS
# #=> 1 2 3 11 12 13 a b c
#
# u.collect{|x| x} # THIS FAILS!!!
# #=> [1, 2, 3, 11, 12, 13, "a", "b", "c"] # expected
# #=> [1..3, 11..13, "a".."c"] # actual

In the example above, each() is redefined. But collect() does not use
the redefined each()!!! It uses Array.each(). Subclassing from some
other class works fine:

class RangeUnion < NotAnArray; ... # gives expected result

It seems that Enumerable is hardwired (built in) in Array. But subclass
should be able to override it. Why isn't that possible?

-Laza
 
D

Daniel Schierbeck

Laza said:
Array includes Enumerable. But when a subclass of Array redefines
each(), then Enumerable still refers to the original Array.each(). Why
is that?
For example:

class RangeUnion < Array
def each
super{|x| x.each{|i| yield i} }
end
end

# u = RangeUnion[1..3, 11..13, "a".."c"]
# u.each{|x| print "#{x} "} # THIS WORKS
# #=> 1 2 3 11 12 13 a b c
#
# u.collect{|x| x} # THIS FAILS!!!
# #=> [1, 2, 3, 11, 12, 13, "a", "b", "c"] # expected
# #=> [1..3, 11..13, "a".."c"] # actual

In the example above, each() is redefined. But collect() does not use
the redefined each()!!! It uses Array.each(). Subclassing from some
other class works fine:

class RangeUnion < NotAnArray; ... # gives expected result

It seems that Enumerable is hardwired (built in) in Array. But subclass
should be able to override it. Why isn't that possible?

I've experienced problems myself when trying to redefine some of
Enumerable's methods. Apparently Array uses its own #collect and #map
methods, plus some others. Maybe if you explicitly re-include Enumerable
into your subclass?


Cheers,
Daniel
 
D

Daniel DeLorme

Laza said:
Array includes Enumerable. But when a subclass of Array redefines
each(), then Enumerable still refers to the original Array.each(). Why
is that?

Your confusion is understandable but you've got the problem backward: that
behavior is not because Enumerable uses Array's each, it's because Array defines
its own version of collect. Look at Array's local (non-inherited) methods:

[].public_methods(false).sort
=> ["&", "*", "+", "-", "<<", "<=>", "==", "[]", "[]=", "assoc", "at", "clear",
"collect", "collect!", "compact", "compact!", "concat", "delete", "delete_at",
"delete_if", "each", "each_index", "empty?", "eql?", "fetch", "fill", "first",
"flatten", "flatten!", "frozen?", "hash", "include?", "index", "indexes",
"indices", "insert", "inspect", "join", "last", "length", "map", "map!",
"nitems", "pack", "pop", "push", "rassoc", "reject", "reject!", "replace",
"reverse", "reverse!", "reverse_each", "rindex", "select", "shift", "size",
"slice", "slice!", "sort", "sort!", "to_a", "to_ary", "to_s", "transpose",
"uniq", "uniq!", "unshift", "values_at", "zip", "|"]

I suppose it was done that way for optimization. Why do you need to subclass
Array, anyway?

Daniel
 
L

Laza

re-including Enumerable does not help. I re-implemented the class by
having an Array member variable instead of inheriting from Array class.
Apparently, not all classes are created equal in Ruby.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,196
Latest member
ScottChare

Latest Threads

Top