Home > Enterprise >  Ruby: How ist the . method working internally?
Ruby: How ist the . method working internally?

Time:10-15

Lets say I create an object a and give it a method .to_i, why can't this object be added to an Integer?

>> a = Object.new
=> #<Object:0x0000000006cfa9d0>
?> def a.to_int
?>   42
>> end
=> :to_int
>> 3   a
(irb):5:in ` ': Object can't be coerced into Integer (TypeError)
        from (irb):5:in `<main>'

CodePudding user response:

You still need to call the to_int method how else does the interpreter know what you want to do?

>> 3   a.to_int

Ruby doesn't do automatic conversion.

>> 3   "5" 

This will give the same error, even though "5" has a perfectly fine to_i method. Btw. to int methods in ruby are ususally called to_i in case you want to keep the consistency.

CodePudding user response:

Adding an integer to an object can be achieved by implementing , e.g.:

class Foo
  def initialize(value)
    @value = value
  end

  def to_i
    @value
  end

  def  (other)
    Foo.new(to_i   other.to_i)
  end
end

Foo.new(5)   4
#=> #<Foo:0x00007fbd22050640 @value=9>

In order to add an instance of Foo to an integer, you have to also implement coerce which takes the left-hand value as an argument and returns an array with both values converted to Foo instances, e.g.:

class Foo
  # ...

  def coerce(other)
    [Foo.new(other.to_i), self]
  end
end

This gives you:

4   Foo.new(5)
#=> #<Foo:0x00007fba600e3e28 @value=9>

The docs for Numeric contain another example.

Internally, coerce is called by Integer# if the argument is not an integer: (C code)

VALUE
rb_int_plus(VALUE x, VALUE y)
{
    if (FIXNUM_P(x)) {
        return fix_plus(x, y);
    }
    else if (RB_TYPE_P(x, T_BIGNUM)) {
        return rb_big_plus(x, y);
    }
    return rb_num_coerce_bin(x, y, ' ');
}

rb_num_coerce_bin calls coerce and then invokes the binary operator on the returned values.

In Ruby this would be: (simplified)

class Integer
  def  (other)
    if other.is_a?(Integer)
      # ...
    else
      x, y = other.coerce(self)
      x   y
    end
  end
end
  • Related