Method that mutates object

On Thu, May 26, 2011 at 2:34 PM, Gary W. [email protected] wrote:

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.

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.

On May 26, 2011, at 12:07 PM, jay s. wrote:

…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
http://en.wikipedia.org/wiki/Tagged_pointer 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 W.

On May 28, 2011, at 2:05 PM, Christopher D. wrote:

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.

My main point was that ‘immutable’ is the wrong term to apply to
fixnum objects (and all other objects) in Ruby. You can add instance
variables to anything.

The original poster asked how to change a fixnum representing the
integer 7 to a fixnum representing the integer 5, which you can’t
do because fixnum semantics are based on identity, not state.

You are correct that in the bignum case you also can’t mutate a
bignum object so that it behaves like a different integer but for
different implementation reasons. In this case, the integer semantics
of a bignum are carried around in hidden state that is not accessible
to the Ruby programmer. You said that the “value…is not dependent
on its state” but I think you meant that the value is not dependent
on the “visible” state or “programmer accessible” state.

Float is another class that implements its semantics via hidden state.

  identity  hidden-state  hidden-state
  semantics semantics     accessible?

fixnum yes no no
symbol yes no no
float no yes no
bignum no yes no
string no yes yes (e.g. String#replace)

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.

I’m not sure what singleton methods have to do with the earlier
discussion. The reason you can’t define singleton methods on Fixnum
instances and other core objects is that it would introduce horrible
performance penalties, not that there is something semantically
awkward about it. In fact its absence is what is awkward.

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.

The reason that I think the behavior of Fixnum, Symbol, NilClass,
TrueClass, and FalseClass should be understand in the context of
identity semantics is because that property manifests itself in the
way that the equality methods work.

For the ‘identity’ classes I listed above,
a == b if and only if a.equal?(b)

For the other built-in numerics with ‘hidden’ state that isn’t true,
the rule is a bit more relaxed:
a.equal?(b) implies a == b (but not the other way around)

There are also performance implications associated with these
implementation
details. For example symbol equality can be determined by comparing
references
while string equality cannot.

Gary W.

On May 28, 2011, at 8:51 PM, Chad P. wrote:

. . . and I haven’t even tried adding an instance variable to that module
yet. How should I add an instance variable to my fixnum object if not
with extend?

We are talking about two different things. You are talking about
modifying the singleton class, which you can’t do. It is prohibited
because it would kill performance to dispatch through singleton classes
for some of the core data types.

But you can manually add instance variables:

3.instance_variable_set("@english", “three”)

Or you can modify the Fixnum class:

class Fixnum
attr_accessor :english
end

4.english = “four”

In either case you’ve got fixnum objects with state that can change.

Gary W.

On Sun, May 29, 2011 at 11:06:29AM +0900, Gary W. wrote:

end

4.english = “four”

In either case you’ve got fixnum objects with state that can change.

Thanks for clearing that up.

I really like how this post clearly explains the declarative differences
between class and instance methods while keeping it straight on the
point. Nicely done!

Brian C. wrote in post #1001047:

jay s. wrote in post #1001040:

Say I want to extend the built in Array class with some useless function
called crazy()

class Array
def crazy
…do something…
end
end

I’m a bit confused

That does appear to be the case :slight_smile: You might want to work through some
documentation. This one is good:
Programming Ruby: The Pragmatic Programmer's Guide

And continue experimenting within irb of course.

Regards,

Brian.

On Sun, May 29, 2011 at 09:29:41AM +0900, Gary W. wrote:

My main point was that ‘immutable’ is the wrong term to apply to
fixnum objects (and all other objects) in Ruby. You can add instance
variables to anything.

I must be doing something wrong, then:

irb(main):001:0> module Mod
irb(main):002:1> end
=> nil
irb(main):003:0> bar = 'bar'
=> "bar"
irb(main):004:0> bar.extend Mod
=> "bar"
irb(main):005:0> foo = 1
=> 1
irb(main):006:0> foo.extend Mod
TypeError: can't define singleton
        from (irb):6:in `extend_object'
        from (irb):6:in `extend'
        from (irb):6
        from /usr/bin/irb1.9.1:12:in `<main>'

. . . and I haven’t even tried adding an instance variable to that
module
yet. How should I add an instance variable to my fixnum object if not
with extend?

Wow. cool post. I’d like to write like this too – taking time and real
hard work to make a great article… but I put things off too much and
never seem to get started. Thanks though.http://wordcookiesgame.com/
http://hillclimbracing-2.com/
http://fivenightsatfreddys-4.com/
http://hotmailcomsignin.email/