From: Gary Wright Date: 2011-05-27T06:34:43+09:00 Subject: Re: Method that mutates object 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. A consequence of this property is that having a *reference* to a fixnum is all you need to interact with the object. The underlying object doesn't even have to 'exist' within the runtime (i.e. there is no memory allocated for every fixnum object). The runtime can emulate the behavior of fixnum objects simply by manipulating the *references* without ever instantiating the objects. See for more about how this sort of thing is implemented. There are several other Ruby classes that have this behavior and tend to be implemented in this way: nil, true, false from NilClass, TrueClass, and FalseClass respectively and symbols. Going back to your original question about setting x to a new value. Another way of interpreting that request is not that you are mutating the object that x references but instead you are rebinding the variable x to a different object. Ruby variables are simply named containers for object references so if you can replace the reference to the fixnum 7 associated with variable x with a reference to the fixnum 5, you will have 'set x to 5', which is exactly what Ruby's assignment operation does. There are a variety of ways for a Ruby method to gain access to variable bindings that are out of the direct scope of the method but it is generally considered bad form for a method to alter variable bindings outside its scope. Nevertheless, here is one way to do it: class Integer def assign(name, value, binding_object) eval "#{name} = #{value}", binding_object end end >> x = 5 #=> 5 >> x.assign('x', 7, binding) #=> 7 >> x #=> 7 This sort of use of eval and binding is *not* at all common and probably only comes into play with various debugging or programming tools rather than in the normal course of writing Ruby programs. Gary Wright