Вызовы методов оператора Ruby против обычных вызовов методов - PullRequest
12 голосов
/ 05 декабря 2010

Мне интересно, почему вызовы операторных методов не требуют точки? Или, скорее, почему нормальные методы не могут быть вызваны без точки?

Пример

class Foo
  def +(object)
    puts "this will work"
  end
  def plus(object)
    puts "this won't"
  end
end 
f = Foo.new
f + "anything" # "this will work"
f plus "anything" # NoMethodError: undefined method `plus' for main:Object

Ответы [ 5 ]

12 голосов
/ 06 декабря 2010

Ответ на этот вопрос, в значительной степени каждый вопрос о дизайне языка: «Просто потому что». Языковой дизайн представляет собой серию в основном субъективных компромиссов. И для большинства из этих субъективных компромиссов только правильный ответ на вопрос, почему что-то так и есть, просто «потому что Матц так сказал».

Конечно, есть и другие варианты:

  • Лисп вообще не имеет операторов . +, -, ::, >, = и т. Д. Являются просто обычными допустимыми именами функций (собственно именами переменных), подобно foo или bar?

    (plus 1 2)
    (+ 1 2)
    
  • Smalltalk почти не имеет операторов. Единственный специальный корпус Smalltalk состоит в том, что методы, которые состоят только из символов оператора, не должны заканчиваться двоеточием. В частности, поскольку нет операторов, все вызовы методов имеют одинаковый приоритет и оцениваются строго слева направо: 2 + 3 * 4 равно 20, а не 14.

    1 plus: 2
    1 + 2
    
  • Scala почти не имеет операторов. Так же, как Lisp и Smalltalk, *, -, #::: и т. Д. Являются просто допустимыми именами методов. (На самом деле они также являются допустимыми именами классов, признаков, типов и полей.) Любой метод можно вызывать как с точкой, так и без нее. Если вы используете форму без точки, а метод принимает только один аргумент, вы можете также оставить скобки. Scala имеет приоритет, хотя и не определяется пользователем; это просто определяется первым символом имени. В качестве дополнительного поворота имена методов операторов, заканчивающиеся двоеточием, инвертированы или ассоциированы справа, т.е. a :: b эквивалентно b.::(a), а не a.::(b).

    1.plus(2)
    1 plus(2)
    1 plus 2
    1.+(2)
    1 +(2)
    1 + 2
    
  • В Haskell любая функция, имя которой состоит из символов оператора, считается оператором. Любая функция может рассматриваться как оператор, заключая ее в обратные тики, а любой оператор можно рассматривать как функцию, заключая ее в квадратные скобки. Кроме того, программист может свободно определять ассоциативность, фиксированность и приоритет для пользовательских операторов.

    plus 1 2
    1 `plus` 2
    (+) 1 2
    1 + 2
    

Нет особой причины, по которой Ruby не может поддерживать пользовательские операторы в стиле, подобном Scala. есть причина, по которой Ruby не может поддерживать произвольные методы в позиции оператора, просто потому что

foo plus bar

уже уже законно, и, таким образом, это было бы несовместимым задом наперед.

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

puts(!true)

законно, но

puts(not true)

не является. Единственная причина , почему это так, заключается в том, что Матц использовал синтаксический анализатор LALR (1) для синтаксического анализа не-LALR (1) языка. Если бы он разработал язык first , он бы никогда не выбрал парсер LALR (1), и выражение было бы допустимым.

Функцией Refinement, обсуждаемой в настоящее время на ruby-core, является другой пример. То, как это указано в настоящее время, сделает невозможным для оптимизации вызовов методов и встроенных методов, , даже если рассматриваемая программа фактически не использует Refinement s вообще . С помощью простой настройки он может быть столь же выразительным и мощным, что и гарантируют, что затраты на пессимизацию будут понесены только для областей, которые на самом деле используют Refinement с. По-видимому, единственная причина , почему был указан таким образом, заключается в том, что a) проще было создавать прототипы таким образом, и b) YARV не не имеет оптимизатора, так что никто даже надоело думать о последствиях (ну, никто, кроме Чарльза Оливера Наттера).

Итак, для в основном любого вопроса, который у вас есть о дизайне Ruby, ответ почти всегда будет либо «потому что Матц так сказал», либо «потому что в 1993 году это было проще реализовать таким образом».

8 голосов
/ 06 декабря 2010

Реализация не имеет дополнительной сложности, которая была бы необходима для общего определения новых операторов.

Вместо этого в Ruby есть синтаксический анализатор Yacc, который использует статически определенную грамматику. Вы получаете встроенные операторы и все. Символы встречаются в фиксированном наборе предложений в грамматике. Как вы заметили, операторы могут быть перегружены, что больше, чем предлагает большинство языков.

Конечно, это не потому, что Мац был ленивым.

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

3 голосов
/ 05 декабря 2010

Поскольку в Ruby есть «синтаксический сахар», который позволяет использовать различные удобные синтаксисы для заданных ситуаций.Например:

class Foo
  def bar=( o ); end
end

# This is actually calling the bar= method with a parameter, not assigning a value
Foo.new.bar = 42

Вот список выражений оператора , которые могут быть реализованы как методы в Ruby.

2 голосов
/ 06 декабря 2010

Поскольку синтаксис Ruby был разработан так, чтобы выглядеть примерно как популярные языки OO, и те используют оператор точки для вызова методов. Язык, который он позаимствовал у своей объектной модели, Smalltalk, не использовал точки для сообщений и на самом деле имел довольно «странный» синтаксис, который многие люди находили отталкивающим. Ruby называют «Smalltalk с синтаксисом Algol», где Algol - это язык, который дал нам соглашения, о которых вы здесь говорите. (Конечно, на самом деле существует больше различий, чем просто синтаксис Алгола.)

0 голосов
/ 05 декабря 2010

Отсутствие скобок было неким «преимуществом» для ruby ​​1.8, но с ruby ​​1.9 вы даже не можете написать method_0 method_1 some param, оно будет отклонено, поэтому язык переходит скорее к строгой версии вместо freeforms.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...