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.

···

--
Posted via http://www.ruby-forum.com/\.

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.

tamouse mailing lists wrote in post #1105640:

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 `<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:

--
Posted via http://www.ruby-forum.com/\.

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'...

--
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 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

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 `<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?

Kind regards

robert

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

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:

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