Почему Ruby не поддерживает I++ или I- (операторы инкремента/декремента)?

оператор pre/post increment/decrement (++ и --) - довольно стандартный синтаксис языка программирования (по крайней мере, для процедурных и объектно-ориентированных языков).

почему Ruby не поддерживает их? Я понимаю, что вы могли бы сделать то же самое с += и -=, но это просто кажется странно произвольным, чтобы исключить что-то подобное, тем более, что это так лаконично и традиционно.

пример:

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 пойми!--5-- > является неизменным, но если += может просто instanciate новый Fixnum и установить его, почему бы не сделать то же самое для ++?

согласованность в назначениях, содержащих = характер единственная причина этого, или я что-то упускаю?

9 ответов


вот как МАЦ(Юкихиро Мацумото) объясняет это в старом нить:

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.

одна из причин заключается в том, что до сих пор каждый оператор присваивания (т. е. оператор, который изменяет переменную) имеет = в нем. Если добавить ++ и --, это не так.

другая причина заключается в том, что поведение ++ и -- часто путают люди. Case in point: возвращаемое значение i++ в вашем примере будет 1, а не 2 (новое значение i было бы 2, однако).


это не принято в языках OO. На самом деле, нет ++ в Smalltalk, язык, который придумал термин "объектно-ориентированное программирование" (и язык Ruby наиболее сильно влияют). Вы имеете в виду, что это обычное в C и языки, близко имитирующие C. Ruby, имеют несколько C-подобный синтаксис,но он не рабски придерживается традиций C.

что касается того, почему это не в Ruby: Matz не хотел этого. Это действительно окончательное причина.

причина, по которой такая вещь не существует в Smalltalk, заключается в том, что это часть переопределяющей философии языка, что назначение переменной принципиально отличается вид вещь, чем отправка сообщения объекту - это на другом уровне. Это мышление, вероятно, повлияло на Matz в разработке Ruby.

было бы возможно включить его в Ruby - вы могли бы легко написать препроцессор, который преобразует все ++ на +=1. но очевидно, мацу не нравилась идея оператора, выполняющего "скрытое задание"."Также кажется немного странным иметь оператор со скрытым целочисленным операндом внутри него. Ни один другой оператор в языке не работает таким образом.


Я думаю, есть еще одна причина:++ в Ruby не было бы удаленно полезно, как в C и его прямых преемниках.

причина в том, что for ключевое слово: хотя это важно в C, это в основном лишнее в Ruby. Большая часть итерации в Ruby выполняется с помощью перечисляемых методов, таких как each и map при итерации через некоторую структуру данных и Fixnum#times метод, когда вам нужно зациклить точное количество раз.

на самом деле, насколько я видел, большую часть времени +=1 используется людьми, недавно перенесенными в Ruby из языков C-style.

короче говоря, это действительно сомнительно, если методы ++ и -- будет использоваться вообще.


Я думаю, что рассуждение Matz о том, что они им не нравятся, заключается в том, что он фактически заменяет переменную новой.

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

теперь, если кто-то может убедить его, что он должен просто позвонить #succ! или нет, это имело бы больше смысла, и избежать проблемы. Вы можете предложить его на ruby core.


Вы можете определить .+ Авто-инкремент оператор:

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

дополнительная информация о " переменной класса "доступна в"переменная класса для увеличения объектов Fixnum".


и, по словам Дэвида Блэка из его книги "обоснованный Рубиист":

некоторые объекты в Ruby хранятся в переменных, как непосредственные значения. Они включают целые числа, символы (которые выглядят так: this) и специальные объекты true, false и нуль. Когда вы присваиваете одно из этих значений переменной (x = 1), переменная имеет значение ценность сама по себе, а не Ссылка на нее. С практической точки зрения это не имеет значения (и это часто будет оставлено как подразумевается, а не изложено неоднократно, при обсуждении ссылок и смежных тем в этой книге). Ruby обрабатывает разыменование ссылок на объекты автоматически; вам не нужно выполните дополнительную работу для отправки сообщения объекту, содержащему, скажем, ссылку на строка, в отличие от объекта, который содержит немедленное целое значение. Но правило представления непосредственного значения имеет несколько интересных последствий, особенно когда дело доходит до чисел. Во-первых, любой объект, который представлен поскольку немедленное значение всегда точно такой же объект, независимо от того, сколько переменные, которым он назначен. Есть только один объект 100, только один объект false, и так далее. Непосредственная, уникальная природа переменных с целочисленной привязкой стоит за отсутствием Ruby операторы pre - и post-increment-то есть, вы не можете сделать это в Ruby: x = 1 х++ # нет такого оператора Причина в том, что в непосредственном присутствии 1 в Х, Х++ будет как 1++, это означает, что вы измените число 1 на число 2-и это делает никакого смысла.


не может ли это быть достигнуто путем добавления нового метода в класс fixnum или Integer?

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

возвращает 2

"разрушительные" методы, похоже, добавляются с ! чтобы предупредить возможных пользователей, поэтому добавление нового метода под названием next! будет в значительной степени делать то, что было запрошено ie.

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

возвращает 2 (так как numb был увеличен)

конечно,next! метод должен был бы проверить, что объект был целочисленной переменной, а не реальное число, но это должны быть доступен.


проверьте эти операторы из семейства C в irb Ruby и проверьте их для себя:

x = 2    # x is 2
x += 2   # x is 4
x++      # x is now 8
++x      # x reverse to 4