Почему Ruby не поддерживает i ++ или i-- (операторы увеличения / уменьшения)? - PullRequest
127 голосов
/ 07 сентября 2010

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

Почему 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

Я понимаю, Fixnum является неизменным, но если += может просто создать новый Fixnum и установить его, почему бы не сделать то же самое для ++?

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

Ответы [ 9 ]

90 голосов
/ 07 сентября 2010

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

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.
28 голосов
/ 07 сентября 2010

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

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

23 голосов
/ 07 сентября 2010

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

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

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

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

10 голосов
/ 08 сентября 2010

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

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

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

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

3 голосов
/ 28 марта 2011

Вы можете определить .+ оператор с приращением:

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

3 голосов
/ 07 сентября 2010

Я думаю, что Мэтцу не нравится, что он на самом деле заменяет переменную новой.

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.

2 голосов
/ 04 апреля 2016

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

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

1 голос
/ 14 августа 2013

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

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

возвращает 2

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

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

возвращает 2 (поскольку онемение было увеличено)

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

0 голосов
/ 15 апреля 2014

Проверьте эти операторы из семейства C в Ruby's irb и проверьте их сами:

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