Методы в Ruby: объекты или нет? - PullRequest
43 голосов
/ 08 апреля 2010

Вдохновленный этим обсуждением , после некоторого поиска в Google я не смог найти ответ на довольно простой вопрос о методах в Ruby: объекты методов или нет?

Существуют разные мнения здесь и там , и я действительно хотел бы услышать, скажем, подробное объяснение.

Мне известен метод Object#method, который принимает имя метода и возвращает экземпляр Method, но, с другой стороны, есть нечто подобное, что вы можете сделать с блоками, чтобы превратить их в Proc экземпляры и блоки не являются объектами, так что же отличает методы?

Ответы [ 6 ]

61 голосов
/ 08 апреля 2010

Методы являются фундаментальной частью Синтаксис Ruby, но они не являются значениями что программы Ruby могут работать. То есть методы Руби не объекты в виде строк, числа и массивы есть. это возможно, однако, чтобы получить метод объект, который представляет данный метод, и мы можем вызывать методы косвенно через объекты метода.

С Язык программирования Ruby :
альтернативный текст http://ecx.images -amazon.com / images / I / 517LDwIEYwL._SL75_.jpg

18 голосов
/ 08 апреля 2010

Ты не скажешь.

Единственный способ получить доступ к методу - это отправить сообщение #method некоторому объекту, который затем вернет объект Method. Но является ли Method объект самим методом? Или это обертка вокруг метода? Или это конвертированная версия оригинального метода?

Вы не можете знать: если вы хотите посмотреть на метод, вы должны вызвать #method, и в этот момент вы определенно получите объект. То, что было до того, как вы назвали #method, вы не можете смотреть, поэтому вы не можете сказать.

Пара точек данных: в Ruby все возвращает значение. Что возвращает def? Он всегда возвращает nil, а не Method объект. И define_method? Возвращает Proc, но не Method (и не UnboundMethod). [Примечание: в Rubinius def возвращает скомпилированный байт-код метода, но все еще не объект Method.]

Если вы посмотрите на 4-й и 5-й абзацы раздела 6.1 спецификации языка Ruby (строки 29-34 и 1-5 на страницах 5 и 6), вы можете ясно увидеть, что между методами и объектами проводится различие , И если вы посмотрите на спецификацию встроенных классов, то обнаружите, что там нет ни Method, ни UnboundMethod, ни Object#method. IOW: вы можете создать полностью совместимый со стандартами интерпретатор Ruby, в котором методы не являются объектами.

Теперь блоки OTOH определенно не являются объектами. Есть много способов построить Proc объектов из блоков, которые затем ведут себя так же, как и исходный блок (lambda, proc, Proc.new, символ &), но сами блоки не являются объектами.

Подумайте об этом так: вы можете передать строку в File.new, чтобы создать объект файла, но это не делает строку файлом. Вы можете передать блок в Proc.new для создания объекта proc, но это не делает блок процедурой.

11 голосов
/ 08 апреля 2010

В Ruby методы и блоки сами по себе не являются нативными или первоклассными объектами. Однако их можно очень легко обернуть в объекты, так что это, как правило, не имеет значения.

Но попробуйте и помните результат,

a = Object.method(:new).object_id
b = Object.method(:new).object_id
a == b
=> false

В Haskell все значения (включая числа, а также лямбды и функции) являются первоклассными значениями. В каждом аспекте языка к ним относятся одинаково. В Ruby дело обстоит иначе, но его можно приблизить.

2 голосов
/ 17 марта 2012

Объекты и методы не одинаковы, даже если возвращаемое значение для методов - объект, а не ноль. Объекты живут в куче, если только не в области метода, лямбды или процедуры, а сам метод живет в стеке и ему присваивается адрес после интерпретации, тогда как статические и классовые объекты размещаются в куче. Ruby по-прежнему использует C, чтобы интерпретировать его и передать его в структуру VALUE.

0 голосов
/ 15 февраля 2019

В Ruby методы не являются объектами. Это сбивает с толку, потому что есть класс Method, и вы можете получить экземпляры метода. Эти экземпляры являются просто прокси для самого метода. Эти экземпляры предоставляют некоторые полезные функции. У них есть некоторая внутренняя магия, которая связывает их с реальным методом (так что вы можете делать такие вещи, как Method#call), но вы не можете получить к ним доступ (AFAIK).

1.method(:to_s).object_id == 1.method(:to_s).object_id #=> false

Это означает, что либо 1 имеет два #to_s метода (которых он не имеет), либо что то, что возвращается методом #method, на самом деле не сам метод, а некоторый прокси для метода. Если бы методы были на самом деле объектами, у вас бывали ситуации, когда вы могли получить один и тот же экземпляр дважды. Если бы методы были объектами, то вы могли бы делать такие вещи, как установить для них переменную экземпляра, а затем они получить значение этой переменной экземпляра после второго извлечения объекта метода. Вы не можете сделать это. Итак, хотя это может обычно не иметь значения, бывают ситуации, когда я нахожу, что не могу делать то, что хотел бы.

1.method(:to_s).instance_variable_set(:@foo, 'foo') #=> "foo" 
1.method(:to_s).instance_variable_get(:@foo)        #=> nil 
# And just in case you question it...
1.object_id == 1.object_id                          #=> true 
0 голосов
/ 14 января 2015

Поскольку круглые скобки являются необязательными в ruby, объекты метода обычно «скрыты» в том смысле, что вам нужно явно извлечь объект метода с помощью метода method. Однако если вы попытаетесь захватить объект метода, станет совершенно ясно, что он действует как объект. Поскольку Ruby> = 2.1, этим легче воспользоваться, чем когда-либо.

Например, вы можете заставить ваши методы вести себя больше, чем в Javascript (где без символа parens есть объект метода, а пары используются для вызова метода), например:

foo = method def foo
  def a(num)
    3 * num.to_i
  end

  n = yield if block_given?
  a(n || 3)
rescue
  "oops!"
end

def foo.bar(num)
  a(num)
end

foo.class #=> Method
foo() #=> 9
foo.call #=> 9
foo.call{2} #=> 6
foo(){2} #=> 6
foo.call{ raise "blam!" } #=> "oops!"
foo.bar(5) #=> 15

См. Эту суть для версии с этим примером, написанной как тесты.

ответ JRL цитирует книгу Матца, в которой говорится, что методы не являются объектами похожи на строки и т. Д. существуют, но объекты методов реальны, и они не являются чем-то, что действует в качестве паренов / без паренов почти как любой другой рубиновый объект. Это язык с уткой , поэтому я бы сказал, что в моей книге методы квалифицируются как объекты.

...