web-dev-qa-db-ja.com

Rubyのメソッド:オブジェクトかどうか?

このディスカッション に触発されて、グーグルをした後、Rubyのメソッドに関する非常に単純な質問に対する答えを見つけることができませんでした:メソッドはオブジェクトかどうか?

ここそこ という意見がありますが、詳細な説明を聞きたいと思います。

メソッド名を取得してMethodインスタンスを返すObject#methodメソッドを知っていますが、一方で、ブロックを使用してそれらをProcインスタンスにすることができる同様のことがあり、ブロックはそうではありません。 tオブジェクトでは、メソッドの違いは何ですか?

45

メソッドはRubyの構文の基本的な部分ですが、Rubyプログラムが操作できる値ではありません。つまり、Rubyのメソッドはオブジェクトではありません文字列、数値、配列のように。ただし、特定のメソッドを表すMethodオブジェクトを取得することは可能であり、Methodオブジェクトを介して間接的にメソッドを呼び出すことができます。

From The Rubyプログラミング言語
alt text

62
JRL

あなたは本当に言うことはできません。

メソッドにアクセスする唯一の方法は、#methodメッセージをオブジェクトに送信することです。これにより、Methodオブジェクトが返されます。しかし、そのMethodオブジェクトはメソッド自体ですか?それとも、メソッドのラッパーですか?それとも、元のメソッドの変換バージョンですか?

わからない:メソッドを見たい場合は、#methodを呼び出す必要があります。その時点で、間違いなくwillオブジェクトを取得します。それが何であったかあなたは#methodと呼んだが、見ることができないので、分からない。

いくつかのデータポイント:Rubyでは、すべてが値を返します。 defは何を返しますか? 常にnilオブジェクトではなく、Methodを返します。そしてdefine_methodProcを返しますが、Method(またはUnboundMethod)は返しません。 [注:Rubiniusでは、defはメソッドのコンパイル済みバイトコードを返しますが、それでもMethodオブジェクトは返しません。]

Ruby言語仕様(5ページと6ページの29-34行目と1-5行目)のセクション6.1の4番目と5番目の段落を見ると、次のことがはっきりとわかります。メソッドとオブジェクトの違い。組み込みクラスの仕様を見ると、そこにはMethodUnboundMethodも入っておらず、Object#methodも入っていないことがわかります。IOW :完全に標準に準拠したRubyインタプリタを構築できます。このインタプリタでは、メソッドではありませんオブジェクトです。

さて、OTOHを確実にブロックしますではありませんオブジェクト。ブロックからオブジェクトを構築Procする方法はたくさんあり、元のブロックと同じ動作をします(lambdaprocProc.new& sigil)ですが、ブロック自体はオブジェクトではありません。

このように考えてください。文字列をFile.newに渡してファイルオブジェクトを作成できますが、それでは文字列がファイルになりません。ブロックをProc.newに渡してprocオブジェクトを作成することはできますが、それによってブロックがprocになるわけではありません。

18
Jörg W Mittag

Rubyでは、メソッドとブロックは、それ自体、ネイティブまたはファーストクラスのオブジェクトではありません。ただし、オブジェクトで簡単にラップできるため、通常は違いはありません。

しかし、試してみて、その結果を覚えておいてください、

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

Haskellでは、すべての値(数値、ラムダ、関数を含む)はファーストクラスの値です。言語のあらゆる面で、それらはすべて同等に扱われます。これはRubyには当てはまりませんが、概算できます。

11
yfeldblum

メソッドの戻り値がオブジェクトであり、nilでない場合でも、オブジェクトとメソッドは同じではありません。メソッド、ラムダ、またはprocスコープ内にない限り、オブジェクトはヒープ上に存在し、メソッド自体はスタック上に存在し、静的オブジェクトとクラスオブジェクトがヒープに割り当てられている間、解釈後にアドレスが割り当てられます。 Rubyは、引き続きCを使用して解釈し、VALUE構造体に渡します。

2
bvrwoo_3376

Rubyでは、メソッドはオブジェクトではありません。 Methodクラスがあり、Methodのインスタンスを取得できるため、これは混乱を招きます。これらのインスタンスは、メソッド自体の単なるプロキシです。これらのインスタンスは、いくつかの便利な機能を提供します。それらには、実際のメソッドに接続するいくつかの内部魔法があります(したがって、Method#callのようなことを行うことができます)が、実際にそのようなものにアクセスすることはできません(AFAIK)。

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

これは、1に2つの#to_sメソッドがある(ない)か、メソッド#methodによって返されるものが実際にはメソッド自体ではなく、メソッドのプロキシであることを意味します。メソッドが実際にオブジェクトである場合、同じインスタンスを2回取得できる状況が発生します。メソッドがオブジェクトの場合、メソッドにインスタンス変数を設定するなどの操作を実行できます。後で、メソッドオブジェクトを2回取得した後、そのインスタンス変数の値を取得します。あなたはそれをすることはできません。ですから、一般的に違いはないかもしれませんが、やりたいことができない場合があります。

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
Huliax

Rubyでは括弧はオプションであるため、メソッドオブジェクトは通常、methodメソッドを介してメソッドオブジェクトを明示的にフェッチする必要があるという意味で「非表示」になっています。ただし、メソッドオブジェクトをキャプチャしようとすると、オブジェクトのように機能することが非常に明確になります。 Ruby> = 2.1なので、これはこれまで以上に簡単に利用できます。

たとえば、次のように、メソッドをJavascriptの場合と同じように動作させることができます(親はメソッドオブジェクトではなく、親はメソッドの呼び出しに使用されます)。

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の答え メソッドはオブジェクトではない文字列などのようにオブジェクトではないが、メソッドオブジェクトは本物であり、その他parens/no-parensのものよりも、他のRubyオブジェクトとほとんど同じように動作します。これは ダックタイピング言語 なので、メソッドは次のように修飾されます。私の本の中のオブジェクト。

0
Andrew