Issue #7342 has been updated by jballanc (Joshua Ballanco).


I would expect something like the following patch makes more sense?

diff --git a/string.c b/string.c
index c63f59a..c9eed27 100644
--- a/string.c
+++ b/string.c
@@ -2385,8 +2385,12 @@ rb_str_cmp_m(VALUE str1, VALUE str2)
     long result;
 
     if (!RB_TYPE_P(str2, T_STRING)) {
-	if (!rb_respond_to(str2, rb_intern("to_str"))) {
-	    return Qnil;
+	if (rb_respond_to(str2, rb_intern("to_str"))) {
+            VALUE tmp = rb_funcall(str2, rb_intern("to_str"), 0);
+            if (!RB_TYPE_P(tmp, T_STRING)) {
+              return Qnil;
+            }
+            result = rb_str_cmp(str1, tmp);
 	}
 	else if (!rb_respond_to(str2, rb_intern("<=>"))) {
 	    return Qnil;

----------------------------------------
Bug #7342: String#<=> checks for a #to_str method on other but never uses it?
https://bugs.ruby-lang.org/issues/7342#change-32889

Author: jballanc (Joshua Ballanco)
Status: Open
Priority: Normal
Assignee: 
Category: 
Target version: 
ruby -v: 2.0.0


=begin
This isn't exactly a bug, as much as a request for clarification. I was looking at the semantics of the (({<=>})) operator and noticed something curious. For most classes, when evaluating (({thing <=> other})), if (({other})) is not of a compatible type, then (({nil})) is returned.

The exceptions (as far as I can find) are String and Time. For the Time class, if (({other})) is not a kind of (({Time})), then the reverse comparison (({other <=> thing})) is tried and the inverse of this result is returned (if not nil). For String, the reverse comparison is only tried IF (({other.respond_to?(:to_str)})), HOWEVER the referenced (({other.to_str})) method is never called. For example:

    class NotAString
      def <=>(other)
        1
      end
      def to_str
        raise "I'm not a string!"
      end
    end
    
    "test" <=> NotAString.new #=> -1

This seems very counterintuitive to me. I would expect that if my class implemented (({to_str})), that the return value of this would be used for comparison.
=end



-- 
http://bugs.ruby-lang.org/