143

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 new Fixnum 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?

Jeremy
  • 1
  • 85
  • 340
  • 366
Andy_Vulhop
  • 4,699
  • 3
  • 25
  • 34
  • 2
    Grep ruby source code for such operators. If there are none - Matz doesn't like 'em. – Eimantas Sep 07 '10 at 16:29
  • You can't do preincrement with a `+=` operator. In C I try to use `++`/`--` only inside conditionals, preferring for the more literal `+=`/`-=` in a basic statement. Probably because I learned Python (long after C though...) – Nick T Sep 07 '10 at 16:35
  • 1
    Wasn't there a question like this for Python just yesterday? – BoltClock Sep 07 '10 at 16:41
  • 1
    @Eimantas well obviously the creator(s) of the language didn't like them. It's too common to overlook. I was wondering WHY, which has somewhat been clarified by answers below. – Andy_Vulhop Sep 07 '10 at 16:42
  • @BoltClock Wouldn't know. I don't read many python questions, nor was I on SO yesterday. – Andy_Vulhop Sep 07 '10 at 16:43
  • @Andy: that's OK, it was just a passing remark. – BoltClock Sep 07 '10 at 16:46
  • 2
    i think this is (almost) a model SO question. It is not something that is not easily googleable to get a considered reply. It is quite clear and specific in what answer is required and the answer sheds light on a facet of programming that can make one think more broadly than just the core of the question. – PurplePilot Sep 08 '10 at 08:06

9 Answers9

106

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ä <aleksi.niemela@cinnober.com> 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.
atw
  • 5,428
  • 10
  • 39
  • 63
Brian
  • 6,820
  • 3
  • 29
  • 27
  • 12
    2 and 3 seem contradictory. If self assignment is bad, why are `+=`/`-=` ok? And wouldn't `1+=1` be just as bad? (It fails in IRB with `syntax error, unexpected ASSIGNMENT`) – Andy_Vulhop Sep 07 '10 at 16:44
  • 3
    (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. – cHao Sep 07 '10 at 16:57
  • 6
    Maybe I am missing something here. `+=` replaces the object the variable references with a whole new object. You can check this by calling `i.object_id` before and after `i+=1`. Why would that be any more technically tricky to do with `++`? – Andy_Vulhop Sep 07 '10 at 17:09
  • 7
    @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). – Chuck Sep 07 '10 at 18:08
  • 3
    In 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. – Steve Midgley Sep 17 '14 at 03:20
32

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

sepp2k
  • 363,768
  • 54
  • 674
  • 675
  • 4
    More 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. – Andy_Vulhop Sep 07 '10 at 16:45
  • what about this: a.capitalize! (implicit assignment of a) – Luís Soares Jul 06 '16 at 22:31
  • 1
    @LuísSoares `a.capitalize!` does not reassign `a`, it will mutate the string that `a` refers to. Other references to the same string will be affected and if you do `a.object_id` before and after the call to `capitalize`, you'll get the same result (neither of which would be true if you did `a = a.capitalize` instead). – sepp2k Jul 06 '16 at 22:46
  • so is `a.capitalize!` different from `a = a.capitalize`? (I'm learning Ruby; thanks) – Luís Soares Jul 06 '16 at 22:47
  • ok I read your answer again. I got it. There's a new pointer created. But in practice is the same right? – Luís Soares Jul 06 '16 at 22:49
  • 1
    @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 have `def 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 of `my_name` will now be `"LUIS"`, whereas it would be unaffected if you had used `capitalize` and an assignment. – sepp2k Jul 06 '16 at 23:00
  • 1
    Wow. That's scary... Knowing that in Java strings are immutable.. But with power comes responsibility. Thanks for the explanation. – Luís Soares Jul 07 '16 at 00:34
26

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.

Chuck
  • 234,037
  • 30
  • 302
  • 389
  • 1
    I 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 Jul 23 '14 at 07:37
13

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.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Mladen Jablanović
  • 43,461
  • 10
  • 90
  • 113
  • 1
    This is the best answer imho. ++ is often used for iteration. Ruby does not encourage this type of iteration. – AturSams Jul 23 '14 at 07:39
4

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

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Sony Santos
  • 5,435
  • 30
  • 41
  • Note though that this only works because you're changing the value of the internal variable `@value`, you're not actually changing the value of `i` at all. And apart from the increment and decrement operators, `Variable` isn't very useful as a `Fixnum` replacement (as @sony-santos points out in the linked post). – David Moles Dec 01 '20 at 23:05
3

I think Matz' reasoning for not liking them is that it actually replaces the variable with a new one.

ex:

a = SomeClass.new
def a.go
  'hello'
end
# at this point, you can call a.go
# but if you did an a++
# that really means a = a + 1
# so you can no longer call a.go
# as you have lost your original

Now if somebody could convince him that it should just call #succ! or what not, that would make more sense, and avoid the problem. You can suggest it on ruby core.

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
  • 9
    "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. – Jörg W Mittag Sep 07 '10 at 17:01
2

And in the words of David Black from his book "The Well-Grounded Rubyist":

Some objects in Ruby are stored in variables as immediate values. These include integers, symbols (which look like :this), and the special objects true, false, and nil. When you assign one of these values to a variable (x = 1), the variable holds the value itself, rather than a reference to it. In practical terms, this doesn’t matter (and it will often be left as implied, rather than spelled out repeatedly, in discussions of references and related topics in this book). Ruby handles the dereferencing of object references automatically; you don’t have to do any extra work to send a message to an object that contains, say, a reference to a string, as opposed to an object that contains an immediate integer value. But the immediate-value representation rule has a couple of interesting ramifications, especially when it comes to integers. For one thing, any object that’s represented as an immediate value is always exactly the same object, no matter how many variables it’s assigned to. There’s only one object 100, only one object false, and so on. The immediate, unique nature of integer-bound variables is behind Ruby’s lack of pre- and post-increment operators—which is to say, you can’t do this in Ruby: x = 1 x++ # No such operator The reason is that due to the immediate presence of 1 in x, x++ would be like 1++, which means you’d be changing the number 1 to the number 2—and that makes no sense.

Andy_Vulhop
  • 4,699
  • 3
  • 25
  • 34
Alexander Swann
  • 619
  • 5
  • 15
2

Some objects in Ruby are stored in variables as immediate values. These include integers, symbols (which look like :this), and the special objects true, false, and nil. When you assign one of these values to a variable (x = 1), the variable holds the value itself, rather than a reference to it.

Any object that’s represented as an immediate value is always exactly the same object, no matter how many variables it’s assigned to. There’s only one object 100, only one object false, and so on.

The immediate, unique nature of integer-bound variables is behind Ruby’s lack of pre-and post-increment operators—which is to say, you can’t do this in Ruby:

x=1

x++ # No such operator

The reason is that due to the immediate presence of 1 in x, x++ would be like 1++, which means you’d be changing the number 1 to the number 2—and that makes no sense.

1

Couldn't this be achieved by adding a new method to the fixnum or Integer class?

$ ruby -e 'numb=1;puts numb.next'

returns 2

"Destructive" methods seem to be appended with ! to warn possible users, so adding a new method called next! would pretty much do what was requested ie.

$ ruby -e 'numb=1; numb.next!; puts numb' 

returns 2 (since numb has been incremented)

Of course, the next! method would have to check that the object was an integer variable and not a real number, but this should be available.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Sjerek
  • 19
  • 1
  • 1
    `Integer#next` already exists (more or less), except it's called `Integer#succ` instead (for 'successor'). But `Integer#next!` (or `Integer#succ!`) would be nonsense: remember that methods work on _objects_, not _variables_, so `numb.next!` would be exactly equal to `1.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 `=`. – philomory Aug 12 '16 at 01:16
  • To complete the comment above: and `Integer#pred` to retrieve the predecessor. – Yoni Jun 17 '19 at 12:45