1

Symbol#<=>

simply says: Compares symbol with other_symbol after calling to_s on each of the symbols. Returns -1, 0, +1 or nil depending on whether symbol is less than, equal to, or greater than other_symbol. nil is returned if the two values are incomparable.

I was trying to understand how Symbol#<=> works when returning nil. Doing so I played with the code:

>> :x.to_s
=> "x"
>> 'x'.to_s
=> "x"

From the above IRB code I thought the return value will be 0. But the actual is nil. As doc says that before using <=> operator to_s is applied both the RHO and LHO. But here the below code is not supporting that principle, seems to me.

>> :x <=> "x"
#=> nil

So I tried to see the source code,to answer myself:

static VALUE
sym_cmp(VALUE sym, VALUE other)
{
    if (!SYMBOL_P(other)) {
        return Qnil;
    }
    return rb_str_cmp_m(rb_sym_to_s(sym), rb_sym_to_s(other));
}

Looking at the source code it is clear that if RHO is not the object of class Symbol, nil will be returned. Let's see the something more in IRB:

>> "x" <=> :x
#=> nil

Again nil. The source code saying that rb_str_cmp_m(rb_sym_to_s(sym),rb_sym_to_s(other)) will be executed now. So now I went to the see the source code of STRING.C. So we are basically pasing the rb_str_cmp_m(???,"x"). Now the I found from github:(? means don't know what value)

rb_str_cmp_m(VALUE str1, VALUE str2)
{
    int result;

    if (!RB_TYPE_P(str2, T_STRING)) {
VALUE tmp = rb_check_funcall(str2, rb_intern("to_str"), 0, 0);
if (RB_TYPE_P(tmp, T_STRING)) {
result = rb_str_cmp(str1, tmp);
}
else {
return rb_invcmp(str1, str2);
}
    }
    else {
result = rb_str_cmp(str1, str2);
    }
    return INT2FIX(result);
}

But the above code I couldn't understand.But I beleieve it has the answer how nil is producing when LHO is not the object of class Symbol.

Can anyone help me here to understand how the nil is coming when LHO is not sym?

Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
  • Look closely, is not `rb_str_cmp_m(rb_sym_to_s(sym), rb_sym_to_s(other))` that is returning the `nil` is the line above: `if (!SYMBOL_P(other)) { return Qnil; }` – fmendez Mar 17 '13 at 12:33
  • @fmendez yes see closely that `other` is `RHO`. I am talking about `LHO`. It first checks the `RHO` if `sym` or not. If `RHO` is `sym` then it just invoke return statement with calling `to_s` on both `LHO and RHO`. – Arup Rakshit Mar 17 '13 at 12:35
  • Perhaps you're confused in thinking that <=> is an operator (hence you talking about LHO and RHO). It's not really an operator, it's a method (hence you should be talking about receiver and arguments). The LHO is the receiver. I've expanded my answer to clarify. – AlexChaffee Mar 17 '13 at 12:42
  • 1
    @AlexChaffee Yes I know its a syntactic sugar. Leave that operator and looking into the source code will give the actual answer.The doc is a bit confusing here. source code is the only option to get the answer :) – Arup Rakshit Mar 17 '13 at 12:43

1 Answers1

3

Symbol and String are different types, and as such are not comparable, just like Fixnum and TrueClass are not comparable. See Why are symbols not frozen strings? for a rant about how they really should be the same (i.e. the case for making class Symbol inherit from class String).

In your first example, the method <=> is being called on a symbol, and the argument is a string, so sym_cmp returns nil.

In your second example, the method <=> is being called on a string, and the argument is a symbol. So the rb_check_funcall sees if it can be naturally converted into a string using to_str; it can't ("NoMethodError: undefined method to_str for :bar:Symbol"), so (eventually) nil is returned in that case too. (We'd have to dig in and see what rb_invcmp does to flesh out that "eventually" there :-))

Community
  • 1
  • 1
AlexChaffee
  • 8,092
  • 2
  • 49
  • 55
  • But do you think the documentation is correct for `nil` looking at source code. I think document is not clear. – Arup Rakshit Mar 17 '13 at 12:30
  • As I read the C source, it's saying "if the other one isn't a symbol, return nil, otherwise convert them both to strings and compare them," which seems correct. – AlexChaffee Mar 17 '13 at 12:32
  • now your update is on the right track. I have given the github link you can use it. – Arup Rakshit Mar 17 '13 at 12:40