Wondering why no "increment" or "decrement" operator in ruby

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?

tamouse mailing lists wrote in post #1105638:

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.

On Sun, Apr 14, 2013 at 10:23 PM, Matthew K. [email protected]
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’…

On Mon, Apr 15, 2013 at 5:38 AM, tamouse mailing lists <
[email protected]> wrote:

On Sun, Apr 14, 2013 at 10:23 PM, Matthew K. [email protected]
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?

Kind regards

robert

tamouse mailing lists wrote in post #1105640:

On Sun, Apr 14, 2013 at 10:23 PM, Matthew K. [email protected]
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’…

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:

irb:001> 1.object_id >> 1
=> 1
irb:002> 328.object_id >> 1
=> 328
irb:003> -2.object_id >> 1
=> -2

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

Every method you send to a Fixnum object goes through the class.

On 2013-Apr-15, at 05:20 , Robert K. 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


remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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 weve shown ranges of numbers and strings. However, as youd 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

irb2.0.0> a = 1
#2.0.0 => 1
irb2.0.0> a.succ
#2.0.0 => 2
irb2.0.0> a = “hello”
#2.0.0 => “hello”
irb2.0.0> a.succ
#2.0.0 => “hellp”

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

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.

-Rob

On Mon, Apr 15, 2013 at 4:01 PM, Rob B.
[email protected]wrote:

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