From: Robert Klemme Date: 2009-10-31T07:20:05+09:00 Subject: Re: Ruby doesn't implement x++ for Fixnum's because ??? On 10/30/2009 08:03 PM, Rick DeNatale wrote: > On Fri, Oct 30, 2009 at 11:05 AM, Robert Klemme > wrote: >> 2009/10/30 RichardOnRails : >> >>> 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"). > > 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. > > The c ++ and -- operators change a variable, NOT a value. 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. But: you would hide the assignment in the syntactic sugared version and this could lead to unexpected behavior, like a = 1 b = a a++ # now why is b still 1??? For someone unaware of the hidden assignment but aware of the fact that the object referenced by a must be mutable to make this work it would be surprising that b is not changed as well. You could only discover that by looking at #object_id of both (or using #equal?). > so in C > > a = 1 > b = a > a++ > > a is now 2, but b is still 1. Yes - and in C++ you can have it otherwise: robert@fussel:~$ g++ x.cc && ./a.out a++=1 a=2 b=2 robert@fussel:~$ cat x.cc #include 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; } robert@fussel:~$ > 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. > > class String > def plus_plus > self << " plus a plus" > end > end > > > a = "A non-plussed string" > b = a > > puts "a is #{a.inspect}" > puts "b is #{b.inspect}" > > a.plus_plus > > puts "a is #{a.inspect}" > puts "b is #{b.inspect}" > > When we run this we see that the result is: > > a is "A non-plussed string" > b is "A non-plussed string" > a is "A non-plussed string plus a plus" > b is "A non-plussed string plus a plus" > > Because in languages like Ruby with object reference variable > semantics, methods can only operate on objects, not the variables > which reference them. > > So if you COULD successfully define Fixnum#++, or Fixnum#plus_plus: > > a = 1 > a++ > > could only change the singleton instance of 1 into 2, which probably > isn't something you'd really want to do. Not necessarily. If this was implemented in the language the sequence "1" would be an object constructor in the same way as string "constants" are. robert@fussel:~$ ruby1.8 -e '2.times { puts "foo".object_id }' -605970738 -605970758 That would the only reasonable way to do it. Then there would be no singleton instance which in turn would have the said performance implications. I would consider the example from Fortran that you presented (changing the value of the constant 1) rather a bug either in the language implementation or in the design. This does not mean that other languages would have to repeat that. :-) Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/