2010-09-07 2 views
116

Оператор pre/post increment/decment (и --) - довольно стандартный синтаксис языка программирования (как правило, для процедурных и объектно-ориентированных языков).Почему Ruby не поддерживает i ++ или i-- (операторы 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 и установить его, почему бы не сделать то же самое для ++?

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

+2

Grep ruby ​​исходный код для таких операторов. Если их нет, Мац их не любит. – Eimantas

+0

Вы не можете сделать preincrement с помощью оператора '+ ='. В C я пытаюсь использовать '++'/'--' только внутри условных выражений, предпочитая более буквальный' + = '/' - = 'в базовом выражении. Наверное, потому что я изучил Python (долго после C, хотя ...) –

+0

Не было ли такого вопроса для Python только вчера? – BoltClock

ответ

82

Вот как Мацумото (Matsumoto Yukihiro) объясняет это в старом thread:

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'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. 
+8

2 и 3 кажутся противоречивыми. Если самосознание плохое, почему '+ ='/'- =' ok? И не было бы «1 + = 1» так же плохо? (Ошибка в IRB с «синтаксической ошибкой, неожиданным назначением») –

+2

(2) означает, что в C вы не изменяете само значение ... вы изменяете содержимое переменной, которая содержит значение. Это слишком мета для любого языка, который проходит по значению.Если есть способ передать что-либо по ссылке в Ruby (и я имею в виду по-настоящему «по ссылке», не передавая ссылку по значению), изменение самой переменной было бы невозможно в рамках метода. – cHao

+4

Может быть, я что-то упустил. '+ =' заменяет объект ссылкой на переменную с целым новым объектом. Вы можете проверить это, вызвав 'i.object_id' до и после' i + = 1'. Почему это было бы более сложно с помощью '++'? –

27

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

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

+4

Больше, чем любая другая причина до сих пор, разумное, что «все присвоения имеют' = 'в них», кажется, имеет смысл. Я могу уважать это как жестокое следование последовательности. –

+0

что об этом: a.capitalize! (неявное назначение a) –

+1

@ LuísSoares 'a.capitalize!' Не переназначает 'a', он будет мутировать строку, к которой относится' a'. Другие ссылки на одну и ту же строку будут затронуты, и если вы выполните 'a.object_id' до и после вызова' capize', вы получите тот же результат (ни одно из них не будет истинным, если вы сделали a = a. капитализировать' вместо этого). – sepp2k

3

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

например:

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

+9

«Вы можете предложить его на рубиновом ядре» ... * После * вы прочитали * и * поняли аргументы во всех других потоках, где это было предложено в прошлый раз, и время до этого, и время до этого, и время до этого и время до этого, и ... Я не был в сообществе Ruby очень долго, но как раз в свое время я помню, как минимум, двадцать таких обсуждений. –

23

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

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

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

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

+1

Я не думаю, что вы предложили препроцессорное предложение; (не эксперт), но я думаю, что i = 42, i ++ вернет 42, где i + = 1 вернет 43. Я неверен в этом? Таким образом, ваше предложение в этом случае было бы использовать i ++, поскольку ++ i обычно используется, что довольно плохо imho и может нанести больше вреда, чем пользы. – zehelvion

8

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

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

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

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

+1

Это лучший ответ imho. ++ часто используется для итерации. Ruby не поддерживает этот тип итераций. – zehelvion

2

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

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 

Более подробная информация о «класса переменных» доступен в «Class Variable to increment Fixnum objects».

1

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

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

возвращает 2

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

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

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

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

+1

'Integer # next' уже существует (более или менее), за исключением того, что вместо него используется' Integer # succ' (для 'successor'). Но 'Integer # next!' (Или 'Integer # succ!') Было бы бессмысленным: помните, что методы работают над _objects_, а не _variables_, поэтому 'numb.next!' Будет в точности равным '1.next!', Что означает, что он будет _базать 1 равным 2_. '++' будет немного лучше, так как это может быть синтаксический сахар для задания, но лично я предпочитаю текущий синтаксис, когда все назначения выполняются с '='. – philomory

-3

Проверьте эти операторы из C-семьи в IRB Руби и проверить их для себя:

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

Это явно неправильно и не работает, так как '(x ++)' является недопустимым выражением в Ruby. – anothermh

2

И в словах Дэвида Блэка из его книги «Обоснованно Rubyist»:

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

+0

Но как вы можете сделать «1.next» тогда? – Magne

Смежные вопросы