Forum: Ruby Wondering why no "increment" or "decrement" operator in ruby

Aa082c8b00a50928e5860dcd70bf2368?d=identicon&s=25 tamouse mailing lists (Guest)
on 2013-04-15 05:09
(Received via mailing list)
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?
3df767279ce7d81db0a5bb30f5136863?d=identicon&s=25 Matthew Kerwin (mattyk)
on 2013-04-15 05:23
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.
Aa082c8b00a50928e5860dcd70bf2368?d=identicon&s=25 tamouse mailing lists (Guest)
on 2013-04-15 05:39
(Received via mailing list)
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'...
3df767279ce7d81db0a5bb30f5136863?d=identicon&s=25 Matthew Kerwin (mattyk)
on 2013-04-15 06:06
tamouse mailing lists wrote in post #1105640:
> 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'...

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.
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (robert_k78)
on 2013-04-15 11:21
(Received via mailing list)
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
Ef3aa7f7e577ea8cd620462724ddf73b?d=identicon&s=25 Rob Biedenharn (Guest)
on 2013-04-15 16:02
(Received via mailing list)
On 2013-Apr-15, at 05:20 , Robert Klemme 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 `<main>'


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
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (robert_k78)
on 2013-04-15 17:42
(Received via mailing list)
On Mon, Apr 15, 2013 at 4:01 PM, Rob Biedenharn
<rob@agileconsultingllc.com>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
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.