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 =3D=3D 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 =3D=3D 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 Wright