Fixnum <=> confusion

Hi,

I am recently learning Ruby, and came across an interesting problem that I do not understand. I was trying to count how many times the sort method was called on an object by overridding <=> to count the number of calls.

I decided to extend Fixnum as follows, but it didn't work. Can anyone tell me why? Thanks.

Bob Evans

Code:

class Fixnum

    @@count = 0

    alias originalComparator <=>

    def <=>(o)
      @@count += 1
      originalComparator(o)
    end

    def Fixnum.count
      @@count
    end
end

Running against it:

>array = [5, 4, 3, 2, 1]
=> [5,4,3,2,1]

>array.sort
=> [1,2,3,4,5]

>Integer.count
=> 0

Expected => 6 > result > 0

Now, if I call 1<=>2 then count increments. Does this mean that Fixnum sorting does not call those operators? Thanks for any help.

Hi,

···

In message "Re: Fixnum <=> confusion" on Wed, 6 Oct 2004 16:43:05 +0900, Robert Evans <robert.evans@acm.org> writes:

Now, if I call 1<=>2 then count increments. Does this mean that Fixnum
sorting does not call those operators? Thanks for any help.

sort skips <=> calls for fixnums to gain performance.

              matz.

Use The Source, Luke :slight_smile:

$ cd /v/build/ruby/ruby-1.8.1-2004.05.02/
$ less array.c

static int
sort_2(ap, bp)
...
    if (FIXNUM_P(a) && FIXNUM_P(b)) {
        if (a > b) return 1;
        if (a < b) return -1;
        return 0;
    }
    if (TYPE(a) == T_STRING && TYPE(b) == T_STRING) {
        return rb_str_cmp(a, b);
    }
...
static VALUE
sort_internal(ary)
    VALUE ary;
{
    qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE),
          rb_block_given_p()?sort_1:sort_2);
    return ary;
}

In other words: Array#sort, when called without a block, special-cases the
comparison of Fixnum to Fixnum and String to String, doing a hard-coded test
instead of calling the spaceship operator.

Try doing:
  array.sort { |a,b| a<=>b }
to force it to do the method call.

Regards,

Brian.

···

On Wed, Oct 06, 2004 at 04:43:05PM +0900, Robert Evans wrote:

Now, if I call 1<=>2 then count increments. Does this mean that Fixnum
sorting does not call those operators? Thanks for any help.

Aha. Thanks for the answer and the friendly reminder about the source.

···

On Oct 6, 2004, at 2:38 AM, Brian Candler wrote:

On Wed, Oct 06, 2004 at 04:43:05PM +0900, Robert Evans wrote:

Now, if I call 1<=>2 then count increments. Does this mean that Fixnum
sorting does not call those operators? Thanks for any help.

Use The Source, Luke :slight_smile:

$ cd /v/build/ruby/ruby-1.8.1-2004.05.02/
$ less array.c

static int
sort_2(ap, bp)
...
    if (FIXNUM_P(a) && FIXNUM_P(b)) {
        if (a > b) return 1;
        if (a < b) return -1;
        return 0;
    }
    if (TYPE(a) == T_STRING && TYPE(b) == T_STRING) {
        return rb_str_cmp(a, b);
    }
...
static VALUE
sort_internal(ary)
    VALUE ary;
{
    qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE),
          rb_block_given_p()?sort_1:sort_2);
    return ary;
}

In other words: Array#sort, when called without a block, special-cases the
comparison of Fixnum to Fixnum and String to String, doing a hard-coded test
instead of calling the spaceship operator.

Try doing:
  array.sort { |a,b| a<=>b }
to force it to do the method call.

Regards,

Brian.