Why does `Kernel :: String" check the result of `to_str`, and` Kernel :: Integer` does not check the result of `to_int`?

Both Kernel::Integerand Kernel::Stringconvert the argument, first trying to cause "long" method ( to_intand to_str, respectively), followed by "short" method ( to_iand to_str, respectively). Both methods check the result class of the "short" method and raise an error if necessary:

[1] pry(main)> class Dummy
[1] pry(main)*   def to_i
[1] pry(main)*     "42"
[1] pry(main)*   end
[1] pry(main)*   def to_s
[1] pry(main)*     42
[1] pry(main)*   end
[1] pry(main)* end;
[2] pry(main)> Integer(Dummy.new)
TypeError: can't convert Dummy to Integer (Dummy#to_i gives String)
from (pry):9:in `Integer'
[3] pry(main)> String(Dummy.new)
TypeError: can't convert Dummy to String (Dummy#to_s gives Fixnum)

This behavior seems logical, since "short" methods should just give an "idea". On the other hand, β€œlong” methods are supposed to be implemented only when the object in question is, in fact, an integer or a string ( see this answer ).

, "" , :

[4] pry(main)> class Dummy
[4] pry(main)*   def to_int
[4] pry(main)*     "42"
[4] pry(main)*   end
[4] pry(main)*   def to_str
[4] pry(main)*     42
[4] pry(main)*   end
[4] pry(main)* end;
[5] pry(main)> Integer(Dummy.new)
=> "42"
[6] pry(main)> String(Dummy.new)
TypeError: can't convert Dummy to String (Dummy#to_str gives Fixnum)

-?

ruby ​​2.1.2, btw:

[7] pry(main)> RUBY_VERSION
=> "2.1.2"
+4
1

, Kernel#Integer, aka rb_f_integer:

  • rb_f_integer rb_convert_to_integer
  • rb_convert_to_integer convert_type(val, "Integer", "to_int", FALSE)
  • convert_type val.to_int , .
  • rb_convert_to_integer :

    tmp = convert_type(val, "Integer", "to_int", FALSE);
    if (NIL_P(tmp)) { // checks if val.to_int is nil. this is the line that causes this
        return rb_to_integer(val, "to_i");
    }
    return tmp;
    

, to_int, , , . , , , . to_i rb_to_integer ( to_int to_int ), to_int . :

class X
  def to_int
    nil
  end

  def to_i
    42
  end
end

class Y
  def to_int
    false
  end

  def to_i
    42
  end
end

p Integer(X.new) #=> 42
p Integer(Y.new) #=> false
+2

Source: https://habr.com/ru/post/1569746/


All Articles