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