From: "David A. Black" Date: 2009-11-11T21:42:19+09:00 Subject: Re: Ruby doesn't implement x++ for Fixnum's because ??? --1926193751-1206044239-1257943327=:10131 Content-Type: MULTIPART/MIXED; BOUNDARY="1926193751-1206044239-1257943327=:10131" This message is in MIME format. The first part should be readable text, while the remaining parts are likely unreadable without MIME-aware tools. --1926193751-1206044239-1257943327=:10131 Content-Type: TEXT/PLAIN; charset=windows-1252; format=flowed Content-Transfer-Encoding: 8BIT Hi -- On Wed, 4 Nov 2009, RichardOnRails wrote: > 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 -- 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) --1926193751-1206044239-1257943327=:10131-- --1926193751-1206044239-1257943327=:10131--