Hi --
Hi Robert,
Thank you for your thoughtful and extensive responses. I apologized
earlier for my sloppy analysis. I hope the following offers higher
quality.
(a) You say, in part:
“... immutable numbers? First, it avoids errors that could be caused
by aliasing (two objects refer the same object, one of them changes
it, it changes for the other one as well without being expected”
(b) Dave Black, in his truly excellent “The Well-Grounded Rubyist”
says, in part:
“Any object that’s represented as an immediate value is always exactly
the same object” and
“The reason [there’s no x=1; x++] is that , due to the immediate
presence of 1 in x, means you’d be changing 1 into 2,
and that makes no sense”
1. I’d rather discuss this matter in concrete terms rather than
abstractions. Please look at the following method (to generate
results) and two statements:
def show(v)
"Got #{v}, class = #{v.class}, object_id = #{v.object_id}
(v.object_id-1)/2 = #{(v.object_id-1)/2 }"
end
a = 1; show (a) => Got 1; class = Fixnum; object_id = 3; v >> 1
= 1
b = 1; show (b) => Got 1; class = Fixnum; object_id = 3; v >> 1
= 1
a == b => true
And a.equal?(b) is also true.
Both “a” and “b” have their respective values held as immediate values
(embedded in their object_id’s), but they are NOT the same thing
because they’re ultimately held in their respective entries in the
symbol table.
But the symbol table, which contains :a and :b, is not the arbiter of
what constitutes the object 1. The object 1 exists independently of
the symbol table. You can create bindings between that object and one
or more identifiers, but you can do that with any object.
So, object_id’s for Fixnum’s are synthetic. To think
that those object_id’s point to a location in a memory area that
stores the 32-bit 000...001 (in a 32-bit machine/OS) is to contradict
the meaning of immediacy and defeat the very efficiency that immediate
values offer.
I don't think object id's exactly point anywhere. Objects happen to
have unique ids, all of which are synthetic in the sense that they
are, themselves, not the object.
2. Now please consider the following supplement to the statements
above:
a += 1; show (a) => Got 2; class = Fixnum; object_id = 5; v >> 1
= 2
For a += 1 you could substitute anything, like a = 300. It's a
completely new assignment, and completely obliterates any previous
binding.
show (a) => Got 2; class = Fixnum; object_id = 5; v >> 1 = 2
show (b) => Got 1; class = Fixnum; object_id = 3; v >> 1 = 1
The assignment of “a += 1” to “a” changed a’s object_id to embed a new
value: 2.
I'm not sure what you mean by the object_id embedding a value. I would
forget about object_id's, and just look at the objects.
Despite that change of 1 to 2 in a’s object, “b” remains
set to 1. “b” did not suffer the calamity of a universal change of
all Fixnum 1’s to 2’s.
But there is no "a's object" across multiple assignments. The
identifier a has absolutely no continuity of consciousness, so to
speak. It's a reusable, disposable, ad hoc label that can be glued on
to any number of objects in succession. The identifier itself does not
maintain state, and does not "know" how many times it has been used.
a = "hi"
a = "bye"
The second line has absolutely no relation to, or dependency on, the
first. And a += 1 is, essentially, just shorthand for a = a + 1 (i.e.,
all the +=, -=, etc. operators are assignment operators).
So when you do a += 1, you're explicitly saying that you are
discarding any previous binding of a, and creating a new one. Of
course, you can only use this shortcut if a has a + method. But it's
an assignment nonetheless; the calling of the method is not, itself,
an assignment operation. You could equally do:
b = a + 1
a = b
3. Conclusion:
a += 1 is equivalent to a++’s natural meaning. In fact, we further
"Natural"? 
supplement the above statements with:
class Fixnum
def pp # We can’t define ++ because of a compiler restriction.
self + 1
end
end
a=1; show(a.pp) => Got 2; class = Fixnum; object_id = 5; v >> 1
= 2
show(b) => Got 1; class = Fixnum; object_id = 3; v >> 1 = 1
Furthermore, pp works fine on the boundary condition for Fixnum’s on a
common 32-bit cpu/OS, i.e. 2**30-1:
a = 2**30-1; show (a) => Got 1073741823; class = Fixnum; object_id
= 2147483647; v >> 1 = 1073741823
a = 2**30; show (a) => Got 1073741824; class = Bignum; object_id =
22737670; v >> 1 = 11368835
So x++ works fine in the form of pp for positive Fixnum’s. I assume
it’ll work fine for non-positives, also.. A compiler change to allow
“def ++” is necessary to finally add ++ to Fixnum.
I know we've been around the block a few times in this thread already,
but the bottom line is that method calls don't affect local variable
bindings. The parser could presumably be trained to treat ++ as an
assignment operator, but Matz's view of this has always been that he
doesn't want assignment semantics to be delivered in something that
looks like a non-assignment idiom from other languages.
The most important example, I think, is this one:
str = "hi"
=> "hi"
str.object_id
=> 1309270
str.succ!
=> "hj"
str
=> "hj"
str.object_id
=> 1309270
a = 1
=> 1
a.object_id
=> 3
a.succ!
NoMethodError: undefined method `succ!' for 1:Fixnum
You can't increment a in place because the messages you send to a
(like: "Increment yourself in place!") are actually being delivered
to an object, not an identifier.
In that sense, the fact that the identifier holds an immediate value
is actually of secondary interest. Even if it didn't, you'd still be
sending a message to an object. The final destination of a message is
never an identifier; it's always an object. So what you're asking for
has to make complete sense in terms of the object.
David
···
On Wed, 4 Nov 2009, RichardOnRails wrote:
--
The Ruby training with D. Black, G. Brown, J.McAnally
Compleat Jan 22-23, 2010, Tampa, FL
Rubyist http://www.thecompleatrubyist.com
David A. Black/Ruby Power and Light, LLC (http://www.rubypal.com)