1

I was playing with the last expression returned by the method,when it is being invoked via an object.

With the concept below code works.

class Simple
  def foo
    2 + 2
  end
end
#=> nil
simple = Simple.new
#=> #<Simple:0x11eb390>
simple.foo
#=> 4

But why the below code returns such encoded value rather than 15 and 20?

class Fixnum
  def to_s
    self + 5
  end
end
#=> nil
puts 10
#<Fixnum:0x000015>
#=> nil
puts 15
#<Fixnum:0x00001f>
#=> nil

Can anyone help me here to understand the concept?

Edit:

class Fixnum
  def to_s
    self + 5
  end
end
#=> nil
10.to_s
#=> #<Fixnum:0x000029>

Again the same result.

Waseem
  • 8,232
  • 9
  • 43
  • 54
DoLoveSky
  • 777
  • 1
  • 6
  • 17

2 Answers2

3

The contract of to_s requires that you return a String. You are, however, returning a Fixnum. If you violate a contract, all sorts of weird things may happen.

If you correctly return a String from your to_s method, everything works as you might expect:

class Fixnum
  def to_s
    "#{self + 5}"
  end
end

puts 10
# SystemStackError: stack level too deep

Well, okay, "everything works" may have been a bit misleading. But, as you can see, everything happens as you might expect it: puts calls to_s on 10, which adds 5 to 10 returning 15, then it calls to_s on 15, which adds 5 returning 20, then calls to_s on 20 etc.

class Fixnum
  orig_to_s = public_instance_method(:to_s)

  define_method(:to_s) do
    orig_to_s.bind(self + 5).()
  end
end

puts 10
# 15

Now, everything works as expected.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653
  • @DoLoveSky: See the section titled *Method Wrapping* in my answer to this question: http://stackoverflow.com/a/4471202/2988 – Jörg W Mittag Feb 27 '13 at 15:19
0

If you add 5 to self, you get another Fixnum.

When you print the Fixnum whose to_s you have modified not to show the result, you started seeing the resulting object instead of the value of fixnum.

nurettin
  • 11,090
  • 5
  • 65
  • 85