2008/9/25 David M. [email protected]:
On Wednesday 24 September 2008 15:45:13 Kyle S. 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