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

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

Почему 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 и устанавливать его, почему бы не сделать то же самое для ++?

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

Ответ 1

Вот как Matz (Yukihiro Matsumoto) объясняет это в старой ветке :

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

Ответ 2

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

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

Ответ 3

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

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

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

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

Ответ 4

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

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

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

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

Ответ 5

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

Пример:

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! или что нет, это будет иметь больше смысла и избежать проблемы. Вы можете предложить его на рубиновом ядре.

Ответ 6

Вы можете определить оператор self-increment .+:

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

Ответ 7

И в словах Дэвида Блэка из его книги "Хорошо обоснованный рубист":

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

Ответ 8

Не удалось ли это, добавив новый метод в класс fixnum или Integer?

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

возвращает 2

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

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

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

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

Ответ 9

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

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