From: Martin DeMello Date: 2003-08-07T16:25:00+09:00 Subject: Re: What's New and Shiny in Ruby 1.8.0? Harry Ohlsen wrote: > However, if we try > > p a.sort_by { |x| rev(x.bar) } > > we get ... > > sort_by.rb:20:in `dup': can't dup Fixnum (TypeError) > > I tried sticking in an > > if obj.respond_to? :dup > > but that didn't help. It would appear that, while Fixnum responds to > #dup, its response is "I'm sorry, Dave, I'm afraid I can't do that." > :-(. This fixes it: def rev(obj) a = obj.dup rescue (return obj.cmp_inv) class << a alias old_cmp <=> def <=>(other) -old_cmp(other) end end a end class Fixnum def cmp_inv -self end end where for any class not supporting dup, we explicitly define a 'comparative inverse' such that a<=>b = b.cmp_inv<=>a.cmp_inv for all a, b belonging to our class. > That doesn't seem to make a lot of sense to me. I would have thought > it made more sense for Fixnum#dup to just return self. Maybe there's > some good reason for not doing that. In this instance, we definitely don't want Fixnum#dup to return self - the call to dup is to avoid the object itself having its comparator reversed. We could avoid the call to dup altogether by using a delegator, I suppose class RevCmp attr_reader :this def initialize(obj) @this = obj end def <=>(other) other.this <=> @this end # not delegating anything else because this is explicitly a throwaway # object used only inside a sort_by block end def rev(obj) RevCmp.new(obj) end > Alternatively, maybe we need a way for classes to disown methods they > inherit that they don't want to (or logically shouldn't) implement? > Then, Fixnum could disown dup and the respond_to? test would work the > way I was expecting. This breaks some sort of OO principle, I think. martin