Why doesn't Ruby support i++ or i— (increment/

2019-01-01 05:24发布

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?

9条回答
若你有天会懂
2楼-- · 2019-01-01 05:52

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.

查看更多
零度萤火
3楼-- · 2019-01-01 05:53

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.

查看更多
墨雨无痕
4楼-- · 2019-01-01 05:56

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.

查看更多
妖精总统
5楼-- · 2019-01-01 05:58

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.
查看更多
皆成旧梦
6楼-- · 2019-01-01 05:58

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

查看更多
萌妹纸的霸气范
7楼-- · 2019-01-01 05:58

Check these operators from the C-family in Ruby's irb and test them for yourself:

x = 2    # x is 2
x += 2   # x is 4
x++      # x is now 8
++x      # x reverse to 4
查看更多
登录 后发表回答