Why doesn't Ruby support i++ or i-- (increment/decrement operators)?
Solution 1
Here is how Matz(Yukihiro Matsumoto) explains it in an old thread:
Hi,
In message "[ruby-talk:02706] X++?"
on 00/05/10, Aleksi Niemelä <[email protected]> writes:
|I got an idea from http://www.pragprog.com:8080/rubyfaq/rubyfaq-5.html#ss5.3
|and thought to try. I didn't manage to make "auto(in|de)crement" working so
|could somebody help here? Does this contain some errors or is the idea
|wrong?
(1) ++ and -- are NOT reserved operator in Ruby.
(2) C's increment/decrement operators are in fact hidden assignment.
They affect variables, not objects. You cannot accomplish
assignment via method. Ruby uses +=/-= operator instead.
(3) self cannot be a target of assignment. In addition, altering
the value of integer 1 might cause severe confusion throughout
the program.
matz.
Solution 2
One reason is that up to now every assignment operator (i.e. an operator which changes a variable) has a =
in it. If you add ++
and --
, that's no longer the case.
Another reason is that the behavior of ++
and --
often confuse people. Case in point: The return value of i++
in your example would actually be 1, not 2 (the new value of i
would be 2, however).
Solution 3
It's not conventional in OO languages. In fact, there is no ++
in Smalltalk, the language that coined the term "object-oriented programming" (and the language Ruby is most strongly influenced by). What you mean is that it's conventional in C and languages closely imitating C. Ruby does have a somewhat C-like syntax, but it isn't slavish in adhering to C traditions.
As for why it isn't in Ruby: Matz didn't want it. That's really the ultimate reason.
The reason no such thing exists in Smalltalk is because it's part of the language's overriding philosophy that assigning a variable is fundamentally a different kind of thing than sending a message to an object — it's on a different level. This thinking probably influenced Matz in designing Ruby.
It wouldn't be impossible to include it in Ruby — you could easily write a preprocessor that transforms all ++
into +=1
. but evidently Matz didn't like the idea of an operator that did a "hidden assignment." It also seems a little strange to have an operator with a hidden integer operand inside of it. No other operator in the language works that way.
Solution 4
I think there's another reason: ++
in Ruby wouldn't be remotely useful as in C and its direct successors.
The reason being, the for
keyword: while it's essential in C, it's mostly superfluous in Ruby. Most of the iteration in Ruby is done through Enumerable methods, such as each
and map
when iterating through some data structure, and Fixnum#times
method, when you need to loop an exact number of times.
Actually, as far as I have seen, most of the time +=1
is used by people freshly migrated to Ruby from C-style languages.
In short, it's really questionable if methods ++
and --
would be used at all.
Solution 5
You can define a .+
self-increment operator:
class Variable
def initialize value = nil
@value = value
end
attr_accessor :value
def method_missing *args, &blk
@value.send(*args, &blk)
end
def to_s
@value.to_s
end
# pre-increment ".+" when x not present
def +(x = nil)
x ? @value + x : @value += 1
end
def -(x = nil)
x ? @value - x : @value -= 1
end
end
i = Variable.new 5
puts i #=> 5
# normal use of +
puts i + 4 #=> 9
puts i #=> 5
# incrementing
puts i.+ #=> 6
puts i #=> 6
More information on "class Variable" is available in "Class Variable to increment Fixnum objects".
Andy_Vulhop
Updated on March 16, 2021Comments
-
Andy_Vulhop about 3 years
The pre/post increment/decrement operator (
++
and--
) are pretty standard programing language syntax (for procedural and object-oriented languages, at least).Why doesn't Ruby support them? I understand you could accomplish the same thing with
+=
and-=
, but it just seems oddly arbitrary to exclude something like that, especially since it's so concise and conventional.Example:
i = 0 #=> 0 i += 1 #=> 1 i #=> 1 i++ #=> expect 2, but as far as I can tell, #=> irb ignores the second + and waits for a second number to add to i
I understand
Fixnum
is immutable, but if+=
can just instanciate a newFixnum
and set it, why not do the same for++
?Is consistency in assignments containing the
=
character the only reason for this, or am I missing something? -
Andy_Vulhop over 13 years2 and 3 seem contradictory. If self assignment is bad, why are
+=
/-=
ok? And wouldn't1+=1
be just as bad? (It fails in IRB withsyntax error, unexpected ASSIGNMENT
) -
Andy_Vulhop over 13 yearsMore than any other reason so far, the rational that "all assignments have a
=
in them" seems to make sense. I can sort of respect that as a fierce adherence to consistency. -
cHao over 13 years(2) means that in C, you're not altering the value itself...you're altering the contents of the variable that holds the value. That's a bit too meta for any language that passes by value. Unless there's a way to pass something by reference in Ruby (and i mean truly "by reference", not passing a reference by value), altering the variable itself wouldn't be possible within a method.
-
Jörg W Mittag over 13 years"You can suggest it on ruby core" ... After you have read and understood the arguments in all the other threads where it was suggested last time, and the time before that, and the time before that, and the time before that, and the time before that, and ... I haven't been in the Ruby community very long, but just during my time, I remember at least twenty such discussions.
-
Andy_Vulhop over 13 yearsMaybe I am missing something here.
+=
replaces the object the variable references with a whole new object. You can check this by callingi.object_id
before and afteri+=1
. Why would that be any more technically tricky to do with++
? -
Chuck over 13 years@Andy_Vulhop: #3 is explaining why it's technically impossible for assignment to be a method, not why assignment is impossible in general (the poster Matz was replying to thought it might be possible to create a
++
method). -
AturSams almost 10 yearsI don't think you preprocessor suggestion would work; (not an expert) but I think that i= 42, i++ will return 42 where i+=1 would return 43. Am I incorrect in this? So your suggestion in that case would be to use i++ as ++i is normally used which is pretty bad imho and can cause more harm than good.
-
AturSams almost 10 yearsThis is the best answer imho. ++ is often used for iteration. Ruby does not encourage this type of iteration.
-
Steve Midgley over 9 yearsIn Ruby all literals are also objects. So I believe Matz is trying to say that he isn't sure that he likes the idea of dealing with 1++ as a statement. Personally I think this is unreasonable since as @Andy_Vulhop says 1+=2 is just as wack, and Ruby just raises an error when you do this. So 1++ is no harder to handle. Possibly the parser's need to cope with that kind of syntactic sugar is undesirable.
-
anothermh about 8 yearsThis is clearly wrong and does not work, as
(x++)
is an invalid statement in Ruby. -
Luís Soares almost 8 yearswhat about this: a.capitalize! (implicit assignment of a)
-
sepp2k almost 8 years@LuísSoares
a.capitalize!
does not reassigna
, it will mutate the string thata
refers to. Other references to the same string will be affected and if you doa.object_id
before and after the call tocapitalize
, you'll get the same result (neither of which would be true if you dida = a.capitalize
instead). -
Luís Soares almost 8 yearsso is
a.capitalize!
different froma = a.capitalize
? (I'm learning Ruby; thanks) -
Luís Soares almost 8 yearsok I read your answer again. I got it. There's a new pointer created. But in practice is the same right?
-
sepp2k almost 8 years@LuísSoares As I said,
a.capitalize!
will affect other references to the same string. That's very much a practical difference. For example if you havedef yell_at(name) name.capitalize!; puts "HEY, #{name}!" end
and you then call it like this:my_name = "luis"; yell_at(my_name)
, the value ofmy_name
will now be"LUIS"
, whereas it would be unaffected if you had usedcapitalize
and an assignment. -
Luís Soares almost 8 yearsWow. That's scary... Knowing that in Java strings are immutable.. But with power comes responsibility. Thanks for the explanation.
-
philomory over 7 years
Integer#next
already exists (more or less), except it's calledInteger#succ
instead (for 'successor'). ButInteger#next!
(orInteger#succ!
) would be nonsense: remember that methods work on objects, not variables, sonumb.next!
would be exactly equal to1.next!
, which is to say, it would mutate 1 to be equal to 2.++
would be marginally better as it could be syntactic sugar for an assignment, but personally I prefer the current syntax where all assignments are done with=
. -
Magne over 7 yearsBut how come you can do "1.next" then?
-
Yoni almost 5 yearsTo complete the comment above: and
Integer#pred
to retrieve the predecessor. -
prashant over 3 yearsNote though that this only works because you're changing the value of the internal variable
@value
, you're not actually changing the value ofi
at all. And apart from the increment and decrement operators,Variable
isn't very useful as aFixnum
replacement (as @sony-santos points out in the linked post).