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