1

I'm trying to make an Array-like class with chainable methods, but I seem to be screwed because Ruby's Array methods call ::Array.new instead of self.class.new:

class MyArray < Array; end
x = MyArray.new
y = MyArray.new
(x+y).class     # Array, expected MyArray!

I understand that I could go through and re-implement all of Array's methods which call its constructor, but that seems really bogus.

Interestingly, Set DOES work 'correctly':

class MySet < Set; end
x = MySet.new([1,2,3])
y = MySet.new([4,5,6])
(x+y).class     # MySet -- yeah!

What am I missing? Is there a Ruby idiom for subclassing Array in this way? Thanks!

1
  • yeah, things are kind of inconsistent implementation with regard to stuff like this in the stdlib, I've found too. Sorry, I don't think there's any simple magic answer. Commented Sep 28, 2015 at 16:23

2 Answers 2

2

The underlying implementation of + method is different between Array and Set. We can read the source code to find the root cause:

For Array, it uses a new variable to store the generated array:

rb_ary_plus(VALUE x, VALUE y)
{
    VALUE z; 
    long len, xlen, ylen;
    ......
    return z;
}

but for Set, + is alias for: |; it uses dup, which produces a shallow copy of the original Set object, it doesn't generate a new Set object to store the result.

def |(enum)
  dup.merge(enum)
end
Sign up to request clarification or add additional context in comments.

1 Comment

Indeed, Array is (rightly) concerned with efficiency so it seems to alloc the space for xlen+ylen elements and then memcpy's the items together. Makes total sense and I'm happy to see the speed. OTOH, it seems very anti-social for an OO implementation. Might have been better for Array to use its own new(x) implementation for the allocation. Oh well, c'est la vie!
0

yeah, things are kind of inconsistent implementation with regard to stuff like this in the stdlib, I've found too. Sorry, I don't think there's any simple magic answer. There isn't really a ruby idiom, ruby doesn't really want you to do it, and some people have posted advocating for never sub-classing Array or Hash. http://words.steveklabnik.com/beware-subclassing-ruby-core-classes

1 Comment

Excellent article - I wish I had seen it before posting here - thanks so much. I've implemented my class with delegation to Array and wrapping the result, I guess that's where this will end up after all. Thanks for helping out. Much appreciated.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.