2008/9/25 David Masover <ninja / slaphack.com>: > On Wednesday 24 September 2008 15:45:13 Kyle Schmitt wrote: >> I'm wondering what the _right_ way is to go about getting the right >> class with inheritance and super() > > Maybe it's just me, but I often use encapsulation, instead. Same here. In this particular case you need to ensure *all* manipulating methods are overridden in a way that they do not break class invariants (max size for example). Kyle's version for example did not deal properly with #shift, #unshift, #push, #pop, #concat to name a few. Also, since inheritance is a "is a" relationship this could send the wrong message. Can a FixedSizeArray really be used whenever an Array is used? I doubt it. >> The issue is that while << works fine, the results from + and - return >> an Array, not a FixedSizeArray, UNLESS I run the returned value >> through a FixedSizeArray.new(), and somehow, that just seems wrong and >> wasteful. > > I would guess it's a result of C code making assumptions (Array is Core stuff, > after all, so a lot of C) -- maybe something doing the equivalent of > Array.new, rather than self.class.new. Method #coerce is not implemented in your classes. This has to be done in order to make + and - work properly across the board. See here for example http://c2.com/cgi/wiki/wiki?RubyCoerce Basically you need to do something like this: class X def coerce other # this method needs to return proper results # depending on the type of argument case other when Integer: [other, to_i] when Float: [other, to_f] else raise TypeError, "Cannot coerce #{other.inspect}" end end def + other if self.class === other # fake only self.class.new else a, b = other.coerce(self) a + b end end def - other if self.class === other # fake only self.class.new else a, b = other.coerce(self) a - b end end def to_i 1 end def to_f 1.0 end end x = X.new # uncomment next line to see what happens # set_trace_func lambda {|*a| p a} puts x + 10, 20 + x, x + 30.0, 40.0 + x, x + x > With an encapsulated pattern, though, you'd at least be avoiding a new Array > object each time: > # Add some array-ness > include Enumerable > def each *args, &block > @array.each *args, &block #each conventionally returns self which does not happen here. In 1.9 you would even go as far as to do this def each(&b) if b @array.each(&b) self else to_enum(:each) end end > end > end > > > > I have no idea which will be more efficient, though. IMHO you could get rid of the shifting in your version by introducing two position markers. > Also, does this graphing tool need to be fast? If not -- if I understand what > you're trying to do -- you might consider simply shrinking it down to size > (with a single slice call) when you need it. One line is a lot easier to > write than a whole class. Certainly true! Kind regards robert -- use.inject do |as, often| as.you_can - without end