Prev: Thread error "undefined method `keys' for nil:NilClass"
Next: Getting version from PE executables
From: Rick DeNatale on 31 Oct 2009 17:19 On Fri, Oct 30, 2009 at 6:20 PM, Robert Klemme <shortcutter(a)googlemail.com> wrote: > On 10/30/2009 08:03 PM, Rick DeNatale wrote: > How their behavior is defined is completely up to the language designer. > You could make "a++" syntactic sugar for > > (_tmp = a; a = a + 1; _tmp) > > in the same way as "a += 1" is syntactic sugar for "a = a + 1" or "a ||= 10" > is syntactic sugar for "a || a = 10". In fact the sequence in brackets > above would be a completely reasonable way to do it in Ruby: you could use > "a++" in a similar way as in C++ and Java without sacrificing Fixnum's > immutability. And I would argue that you still can't implement ++ for fixnum since there isn't a ++ method, any more than there is a += method. > But: you would hide the assignment in the syntactic sugared version and this > could lead to unexpected behavior, like Which I think gets to the fundamental difference. In C/C++ an integer variable is just a bit-string of a particular length interpreted as a signed (probably 2s complement) integer, and ++ is a operator on the variable which twiddles those bits. In Ruby and languages of its ilk, a variable is a reference to an object, and can only be modified by an assignment, not by a method of the object it happens to be referencing at the moment, whether that object is mutable or not. -- Rick DeNatale Blog: http://talklikeaduck.denhaven2.com/ Twitter: http://twitter.com/RickDeNatale WWR: http://www.workingwithrails.com/person/9021-rick-denatale LinkedIn: http://www.linkedin.com/in/rickdenatale
From: Rick DeNatale on 31 Oct 2009 17:29 On Sat, Oct 31, 2009 at 1:35 PM, Simon Krahnke <overlord(a)gmx.li> wrote: > * Robert Klemme <shortcutter(a)googlemail.com> (23:19) schrieb: > >> Yes - and in C++ you can have it otherwise: >> >> robert(a)fussel:~$ g++ x.cc && ./a.out >> a++=1 >> a=2 >> b=2 >> robert(a)fussel:~$ cat x.cc >> >> #include <stdio.h> >> >> int main( int argc, const char* argv[] ) >> { >> int a = 1; >> int &b = a; >> printf("a++=%d\n", a++); >> printf("a=%d\n", a); >> printf("b=%d\n", b); >> return 0; >> } > > No, you can't: > > $ ./ab > a: 2 @ 0xbfe413f8 > b: 2 @ 0xbfe413f8 > > $ cat ab.cc > #include <iostream> > > int main(void) { > int a = 1; > int &b = a; > a++; > std::cout << "a: " << a << " @ " << &a << std::endl; > std::cout << "b: " << b << " @ " << &b << std::endl; > return 0; > } > > There is only one variable, b is just another name for it. I'm not going to run the experiment, but I believe that if the int &b = a; were changed to int b = a; Then the result would be the same as in Robert's 'surprising' ruby example. Which only points out the different in meaning between a C 'reference' variable, which aliases another variable, and the concept of a ruby variable as a reference to an object. And no, I don't think that adding syntactic sugar to Ruby to make a++ the same as either a += 1 or a = a.succ is a good idea. As a matter of fact, neither of this is REALLY the same as a++, since things like b = a++ should assign the ORIGINAL value of a to b, as opposed to b = ++a Things like post and pre increment/decrement operators in C like languages are best reserved to languages with the same basic structure. To my mind they are akin to the different rules for gender, and agreement in different families of languages. -- Rick DeNatale Blog: http://talklikeaduck.denhaven2.com/ Twitter: http://twitter.com/RickDeNatale WWR: http://www.workingwithrails.com/person/9021-rick-denatale LinkedIn: http://www.linkedin.com/in/rickdenatale
From: RichardOnRails on 3 Nov 2009 22:24 On Oct 30, 11:05 am, Robert Klemme <shortcut...(a)googlemail.com> wrote: > 2009/10/30 RichardOnRails <RichardDummyMailbox58...(a)uscomputergurus.com>: > > > I'll correct my errors and probably have a new theory subsequently. > > IMHO the story goes like this: absence of postfix ++ and -- is a > consequence of the fact that numeric types are immutable in Ruby which > makes an assignment necessary for these operators. Although that > would be doable, it would not immediately be obvious when looking at > "foo++". On the other side, "foo += 1" makes the assignment obvious > while still being pretty concise (you do not have to write "foo = foo > + 1"). > > Which brings us to the question: what is the advantage of 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). Then, it is quite > natural if you consider mathematical numbers: they cannot change. > > Additionally, the expression "1" can always refer to the same object > (in reality it's a bit different but from a Ruby programmer's > perspective the difference is not noticeable) which in fact makes > using numeric constants very efficient (as opposed to the expression > "'foo'" which constructs a new String instance on every invocation, > albeit with a shared char array underneath which eases the pain a > bit). > > This in turn makes integer math pretty efficient because if numbers > were mutable Ruby would have to create a new object for every result > of an operator evaluation. I am not saying that Ruby is ideal for > number crunching but it could be significantly slower if certain > design decisions would have been made differently. > > Kind regards > > robert > > -- > remember.guy do |as, often| as.you_can - without endhttp://blog.rubybestpractices.com/ 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 thats represented as an immediate value is always exactly the same object and The reason [theres no x=1; x++] is that , due to the immediate presence of 1 in x, means youd be changing 1 into 2, and that makes no sense 1. Id 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 Both a and b have their respective values held as immediate values (embedded in their object_ids), but they are NOT the same thing because theyre ultimately held in their respective entries in the symbol table. So, object_ids for Fixnums are synthetic. To think that those object_ids 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. 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 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 as object_id to embed a new value: 2. Despite that change of 1 to 2 in as object, b remains set to 1. b did not suffer the calamity of a universal change of all Fixnum 1s to 2s. 3. Conclusion: a += 1 is equivalent to a++s natural meaning. In fact, we further supplement the above statements with: class Fixnum def pp # We cant 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 Fixnums 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 Fixnums. I assume itll work fine for non-positives, also.. A compiler change to allow def ++ is necessary to finally add ++ to Fixnum. Again, thanks for your responses to my question. Best wishes, Richard
From: Tony Arcieri on 3 Nov 2009 23:14 [Note: parts of this message were removed to make it a legal post.] On Fri, Oct 30, 2009 at 12:03 PM, Rick DeNatale <rick.denatale(a)gmail.com>wrote: > I think that theres a more fundamental problem with ++ in a language > like ruby, which has to do with the difference between objects and > variables. > Personally I see nothing interesting about the behavior of ++ in any mutable state language. > Now, consider not immutable objects, but defining ++ for a mutable > object. I've named the method plus_plus instead of ++ since I can do > the former, but not the latter. > How is ++ any different from << except for << taking an argument? (given hypothetical C-like ++ behavior) There is already extensive precedent in Ruby for destructive method calls that mutate state, and they all lead to the same confusion. There is nothing interesting with Ruby in this regard, except that Ruby does seem to go out of its way to do things immutably by default, which, in my opinion, is pretty cool. But in the end Ruby is still very much a mutable state language. -- Tony Arcieri Medioh/Nagravision
From: Rick DeNatale on 3 Nov 2009 23:17
On Tue, Nov 3, 2009 at 10:25 PM, RichardOnRails <RichardDummyMailbox58407(a)uscomputergurus.com> wrote: > a += 1 is equivalent to a++s natural meaning. In fact, we further > supplement the above statements with: > > class Fixnum > def pp # We cant define ++ because of a compiler restriction. > self + 1 > end > end > So x++ works fine in the form of pp for positive Fixnums. I assume > itll work fine for non-positives, also.. A compiler change to allow > def ++ is necessary to finally add ++ to Fixnum. No x++ doesn't work fine if you want it to act like C's post-increment operator. Let's leave Ruby aside for a moment and consider this snippet of C code. int a = 1; int b = a++ After these two lines a is 2, and b is 1, since a++ returns the original value of a and then increments a. Why this wierd semantic? Because it the original use case was for pointers rather than integers, and it goes back to C originating originally as a kind of high level assembly language for the DEC PDP-11 which had postincrement and predecrement addressing modes used for stepping through strings or arrays. Because pre-ANSI C allowed easy spoofing/overlay of types, it also worked for integers and was used in contexts like for loops for(i = 0; i < max;i++) where the value of the expression i++ was never used, only the side effect that it left a as 1 higher than before was important. Because of this, many C/C++ programmers seem to be unaware or forget that the value of a++ is a, not (a+1). In fact Bjarne Stroustrup used to rib himself by pointing out that the value of C++ was exactly the same as C, because he IS certainly aware of the semantics. Now what happens if we translate my initial snippet into Ruby using your pp method class Integer # Not need to restrict to FixNums is there # Name it pp since ++ isn't a valid Ruby method selector def pp self + 1 end end a = 1 b = a.pp puts "a is #{a}, b is #{b}" Produces not "a is 2, b is 1" as it would if it correctly implemented C language semantics but a is 1, b is 2 just the opposite of what would be expected by a C/C++ programmer who understood the meaning of post-increment ++ The fact of the matter is that you can't write a ++ or a pp method in Ruby which works like the C post-increment because it requires the method to change the value of a variable which is bound to the object and the method only knows what the object knows and the object doesn't know which variable(s) refer to it. consider a = b = c = 1 b.pp There are at least 3 variables which refer to the Fixnum object 1, The fact that that reference is through a special form object id computed by multiplying 1 by 2 and adding 1, as it is in several Ruby implementations, is irrelevant. So is the fact that Fixnums happen to be immutable. No object knows what variables reference it, and wouldn't have a way to directly change those variables bindings anyway. The rebinding of a in a = a.pp doesn't happen in the pp method it happens in the calling context because of the assignment expression there. So if you just want a ++ which returns the incremented value of a fixnum then you can write it as pp, but you really don't need to since Integer#succ does just that. If you want the real semantics of the C/C++ post-increment operator, I'm afraid you'll have to look for it in a C family language, not an object reference semantic language like Ruby. -- Rick DeNatale Blog: http://talklikeaduck.denhaven2.com/ Twitter: http://twitter.com/RickDeNatale WWR: http://www.workingwithrails.com/person/9021-rick-denatale LinkedIn: http://www.linkedin.com/in/rickdenatale |