Seems like every other language I've encountered since learning C way
back in the Jurassic, has had an increment (++) or decrement (--)
operator, and I've been wondering why Ruby doesn't. I haven't gone off
looking for the answer, but I think I have figured out why it can't
work, roughly, in general, and
not-really-knowing-the-deep-implementation reasons why.
Basically, because you cannot do something like this:
1.increment
and expect your 1 to start having the value of 2. Since 1 is an object
that is an instance of Fixnum, and doing
a = 1
basically is just saying `a` points the object `1`, you can't have
`a.increment`, either.
Seems like every other language I've encountered since learning C way
back in the Jurassic, has had an increment (++) or decrement (--)
operator, and I've been wondering why Ruby doesn't. I haven't gone off
looking for the answer, but I think I have figured out why it can't
work, roughly, in general, and
not-really-knowing-the-deep-implementation reasons why.
Basically, because you cannot do something like this:
1.increment
and expect your 1 to start having the value of 2. Since 1 is an object
that is an instance of Fixnum, and doing
a = 1
basically is just saying `a` points the object `1`, you can't have
`a.increment`, either.
Have I got it?
In a word: yes.
You don't have the ability to perform an action on the variable 'a'
except by assignment; all you can do is send messages to the object it
references. And there is always only exactly one 1, and it is never
equal to 2.
Incidentally, if you're using MRI, because of a clever optimisation your
'a' variable literally holds the value `1`, not a reference per se.
I guess I don't understand this last part; I can still call an
instance method on a, so it must be more than just a value..., no? As
I can call an instance method on 1. I guess I don't quite get what you
mean by 'value'...
···
On Sun, Apr 14, 2013 at 10:23 PM, Matthew Kerwin <lists@ruby-forum.com> wrote:
Incidentally, if you're using MRI, because of a clever optimisation your
'a' variable literally holds the value `1`, not a reference per se.
Incidentally, if you're using MRI, because of a clever optimisation your
'a' variable literally holds the value `1`, not a reference per se.
I guess I don't understand this last part; I can still call an
instance method on a, so it must be more than just a value..., no? As
I can call an instance method on 1. I guess I don't quite get what you
mean by 'value'...
In the C code underlying MRI, ruby objects are referred to by integers
called 'VALUE's, which are effectively references to the instantiated
objects. However for fixnums (and the new flonums) the VALUE is
actually a reversibly-mangled version of the actual value.
Here's a transcript from IRB on my 64 bit Linux box in a recent build of
trunk:
Because the numeric value is known, there's no need to instantiate a
"proper" object to encapsulate it; rather the interpreter can look at
the VALUE, see that it has the "is a Fixnum" bits set, and dispatch the
appropriate methods through the Fixnum class.
On that point: Fixnum "objects" don't even have a singleton:
irb:004> class << 1; end
TypeError: can't define singleton
from (irb):4
from /usr/local/bin/irb21:12:in `<main>'
irb:005> a = 1; def a.foo; end
TypeError: can't define singleton
from (irb):5
from /usr/local/bin/irb21:12:in `<main>'
Every method you send to a Fixnum object goes through the class.
···
On Sun, Apr 14, 2013 at 10:23 PM, Matthew Kerwin <lists@ruby-forum.com> > wrote:
I prefer to look at this on the language level and not the MRI
implementation (even though they are closely related). On the language
level the optimization is invisible and hence irrelevant for the reasoning
here. The reason for the absence of an increment operator is that there
was a design decision to make numbers immutable (at least with regard to
their numeric value). If instances of a type are immutable their state
will never change - hence you cannot change them from representing 1 to 2
etc.
Having said that, "++a" could be made syntactic sugar for "a+=1" but that
would not work if a was referencing a String even though String#+ is
defined. The only way out of this would be to make "++a" syntactic sugar
for something like "a+=a.class.one" where Integer would implement "one" as
"return 1". But what would String.one return then?
Kind regards
robert
···
On Mon, Apr 15, 2013 at 5:38 AM, tamouse mailing lists < tamouse.lists@gmail.com> wrote:
On Sun, Apr 14, 2013 at 10:23 PM, Matthew Kerwin <lists@ruby-forum.com> > wrote:
> Incidentally, if you're using MRI, because of a clever optimisation your
> 'a' variable literally holds the value `1`, not a reference per se.
I guess I don't understand this last part; I can still call an
instance method on a, so it must be more than just a value..., no? As
I can call an instance method on 1. I guess I don't quite get what you
mean by 'value'...
Why wouldn't the syntactic sugar for ++a be a=a.succ (for "successor") since that is defined on more types? From the PIckaxe:
So far we’ve shown ranges of numbers and strings. However, as you’d expect from an object- oriented language, Ruby can create ranges based on objects that you define. The only constraints are that the objects must respond to succ by returning the next object in sequence and the objects must be comparable using <=>.
-- Programming Ruby 1.9 & 2.0, p. 93, Ch.6 Standard Types
For String, which does have mutable instances, there's also #succ! to change the object itself.
irb2.0.0> a #2.0.0 => "hello"
irb2.0.0> a = "hello" #2.0.0 => "hello"
irb2.0.0> a.succ #2.0.0 => "hellp"
irb2.0.0> a #2.0.0 => "hello"
irb2.0.0> a.succ! #2.0.0 => "hellp"
irb2.0.0> a #2.0.0 => "hellp"
for --a you could use a=a.pred (for "predecessor"), but that's only defined on Integer (and had no built-in use like #succ does).
irb2.0.0> a = 1 #2.0.0 => 1
irb2.0.0> a.pred #2.0.0 => 0
irb2.0.0> a.pred
NoMethodError: undefined method `pred' for "hello":String
from (irb):5
from /Users/rab/.rbenv/versions/2.0.0-p0/bin/irb:12:in `<main>'
-Rob
···
On 2013-Apr-15, at 05:20 , Robert Klemme wrote:
On Mon, Apr 15, 2013 at 5:38 AM, tamouse mailing lists <tamouse.lists@gmail.com> wrote:
On Sun, Apr 14, 2013 at 10:23 PM, Matthew Kerwin <lists@ruby-forum.com> wrote:
> Incidentally, if you're using MRI, because of a clever optimisation your
> 'a' variable literally holds the value `1`, not a reference per se.
I guess I don't understand this last part; I can still call an
instance method on a, so it must be more than just a value..., no? As
I can call an instance method on 1. I guess I don't quite get what you
mean by 'value'...
I prefer to look at this on the language level and not the MRI implementation (even though they are closely related). On the language level the optimization is invisible and hence irrelevant for the reasoning here. The reason for the absence of an increment operator is that there was a design decision to make numbers immutable (at least with regard to their numeric value). If instances of a type are immutable their state will never change - hence you cannot change them from representing 1 to 2 etc.
Having said that, "++a" could be made syntactic sugar for "a+=1" but that would not work if a was referencing a String even though String#+ is defined. The only way out of this would be to make "++a" syntactic sugar for something like "a+=a.class.one" where Integer would implement "one" as "return 1". But what would String.one return then?
From my Wayback Machine™, about 25 years ago the company I worked for had an internally developed C compiler (yes, back in the stone age before C was even a standard language and gcc was that weird, free compiler) that actually did define ++ and -- for doubles (floating point numbers) as a+=1.0 and a-=1.0 for just this reason.
Why wouldn't the syntactic sugar for ++a be a=a.succ (for "successor")
since that is defined on more types?
Yes, that's even better. But, as you discovered
for --a you could use a=a.pred (for "predecessor"), but that's only
defined on Integer (and had no built-in use like #succ does).
#succ and #pred are not that symmetric in terms of availability. Maybe
Matz also wanted to avoid hiding an assignment inside an operator which
does not contain an equals sign.
And then there are of course the postfix variants of these operators which
need a temp variable or #tap:
a++ -> a.tap { a = a.succ }
Kind regards
robert
···
On Mon, Apr 15, 2013 at 4:01 PM, Rob Biedenharn <rob@agileconsultingllc.com>wrote: