From: Christopher Dicely Date: 2011-05-29T03:05:32+09:00 Subject: Re: Method that mutates object On Thu, May 26, 2011 at 2:34 PM, Gary Wright wrote: > > On May 26, 2011, at 12:07 PM, jay s. wrote: > >> I understand that using String#replace works for the String class, but >> what if you were writing a random method for Integer that takes a number >> and sets it equal to some other number. >> >> Ex. >> >> x = 7 >> >> class Integer >>  def crazy >>    ...set x to 5... >>  end >> end >> >> >> now when you call x the value is 5 > > > This seems like a simple question but it touches on some very deep issues of Ruby's object model.  Understanding the object model is the key to understanding why your question doesn't make sense in Ruby. > > Ruby's fixnum objects are not containers for an integer value.  This means that for any particular fixnum object there is no way to alter it so that it no longer behaves like a 7 and instead behaves like a 5, for example.  The integer semantics of a fixnum object are defined by the object's *identity*, not by any state it carries around (i.e. instance variables or state that is hidden from the programmer but maintained by the runtime). > >>> x = 5       #=> 5 >>> x.object_id #=> 11 >>> y = 7       #=> 7 >>> y.object_id #=> 15 >>> z = 3 + 4   #=> 7 >>> z.object_id #=> 15 >>> z.eql?(y)   #=> true > > In that example you can see that y and z reference the *same* object, which happens to be object 15 in my version of Ruby and which happens to behave like the integer 7.  The Ruby runtime ensures that object 15 always behaves like the integer 7 and that it is the *only* object that behaves like the integer 7. > > And yes, you can attach instance variables to fixnum objects: > >>> a = 2 #=> 2 >>> b = 1 + 1 #=> 2 >>> a.instance_variable_set('@english', 'two') #=> "two" >>> b.instance_variable_get('@english') #=> "two" >>> a.object_id #=> 5 >>> b.object_id #=> 5 > > So you can see that within Ruby's object model there is one and only one fixnum object > that behaves like the integer 2.  That particular object in MRI Ruby 1.9.2 happens to have an > object_id of 5, but that is really just an implementation detail. > > Lots and lots of Rubyists describe fixnum objects as 'immutable', but as shown above with > instance variables, that is simply not an accurate description of Ruby's fixnum objects. The > characteristic that erroneously gets labeled as 'immutability' is that the semantics of a fixnum object > are defined by its *identity* and not by its state. That's actually probably not the best description. While its true that the implementation of the immutability of the arithmetic value of a Fixnum is implemented (in most and possibly all Ruby implementations) through a fixed relationship of that value on the identity of the Fixnum, its worth noting that the value of a Bignum in an arithmetic context is likewise not dependent on its state, even though Bignums -- unlike Fixnums -- are generally not implemented with a fixed relationship between value and identity, such that there can be more than one Bignum object with the same value. The real enforcement of the distinction isn't so much that identity rather than state is used (since this is not true of the implementation of Bignums) but that you can't define singleton methods on objects of the built-in numeric types, and the arithmetic value isn't stored in mutable state (that is, its not in instance variables), so the arithmetic behavior of objects of built-in numeric types can't be overridden on an object-by-object basis by the normal methods Ruby allows for doing that for object behavior. That Fixnums of the same value share object identity is an implementation detail, not the fundamental basis of the arithmetic immutability, since the latter is a feature of Ruby's built-in numerics generally, including those that don't use Fixnum-style identity-sharing.