2010-04-08 11 views
41

Inspiriert von this discussion, nach einigem googlen konnte ich keine Antwort auf eine ziemlich einfache Frage bezüglich Methoden in Ruby finden: sind Methoden Objekte oder nicht?Methoden in Ruby: Objekte oder nicht?

Es gibt verschiedene Meinungen here und there, und ich würde wirklich gerne hören, sagen wir, eine eingehende Erklärung.

Ich bin mir dessen bewusst Object#method Methode, die einen Methodennamen nimmt und gibt eine Method Instanz, aber auf der anderen Seite gibt es eine ähnliche Sache, die Sie mit Blöcken tun können, um sie in Proc Instanzen zu machen, und blockiert aren‘ t Objekte, was macht Methoden anders?

+0

Funktionen sind erstklassige Bürger in Ruby und können in Objekte umgewandelt werden, also warum sich sorgen? Ich denke, die Antwort wird zu niedrig liegen, um viel Sinn zu machen ... –

+3

Sind sie? IMHO, die Tatsache, dass Sie sie in Objekte konvertieren müssen, macht sie nicht-erste Klasse. Das möchte ich auch aus den Antworten lernen. –

Antwort

60

Methoden sind ein wesentlicher Bestandteil der Rubys Syntax, aber sie sind keine Werte , die Ruby-Programme arbeiten auf. Das heißt, Ruby Methoden sind nicht Objekte in der Art, dass Strings, Zahlen und Arrays sind. Es ist möglich, jedoch eine Methode Objekt zu erhalten, das eine bestimmte Methode darstellt, , und wir können Methoden indirekt über Methodenobjekte aufrufen.

Von The Ruby Programming Language:
alt text http://ecx.images-amazon.com/images/I/517LDwIEYwL._SL75_.jpg

+0

Hallo, Wenn Methoden nicht Objekt sind dann wie es möglich ist? 'irb (main): 015: 0> def hallo irb (main): 016: 1> "Hallo" irb (main): 017: 1> Ende => nil irb (main): 018: 0> hi.object_id => 22.452.528 IRB (Haupt): 019: 0> hi.object_id.send Hallo => "Hallo" IRB (main): 020: 0> hi.object_id.send (Hallo) => "hi" ' –

+11

' hi.object_id' ruft zuerst die Methode 'hi' auf und gibt dann die object_id des Ergebnisses zurück (was der String' 'hallo'' ist). –

10

In Ruby sind Methoden und Blöcke an und für sich keine nativen oder erstklassigen Objekte. Sie können jedoch sehr einfach in Objekte eingewickelt werden, so dass es im Allgemeinen keinen Unterschied macht.

Aber ausprobieren, und bedenken Sie sind das Ergebnis,

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

In Haskell, alle Werte (einschließlich Zahlen sowie Lambda-Ausdrücke und Funktionen) erstklassige Werte. In jedem Aspekt der Sprache werden sie alle gleich behandelt. Dies ist in Ruby nicht der Fall, aber es kann angenähert werden.

+0

Gerechtigkeit, Ihr Argument war das gleiche wie meines. Außerdem ist mir keine andere Möglichkeit bekannt, Methoden zurückzugeben, daher scheint #method (methoden_name) die einzige Möglichkeit zu sein, überhaupt auf eine Methode zu verweisen, abgesehen davon, dass sie nach ihrem ursprünglichen Objekt benannt wird. –

+1

Die einzige Sache, die Ihre object_id beweist, ist, dass sie nicht sofort sind. 'a = 1.0.object_id; b = 1.0.object_id; a == b # => false' –

18

Man kann nicht wirklich sagen.

Die einzige Möglichkeit, auf eine Methode zuzugreifen, besteht darin, die Nachricht #method an ein Objekt zu senden, das dann ein Objekt Method zurückgibt. Aber ist das Method Objekt die Methode selbst? Oder ist es ein Wrapper um die Methode? Oder ist es eine konvertierte Version der ursprünglichen Methode?

Sie können nicht wissen: Wenn Sie eine Methode betrachten möchten, müssen Sie #method anrufen, an diesem Punkt erhalten Sie definitiv wird ein Objekt erhalten. Was es war vor Sie angerufen #method können Sie nicht betrachten, daher können Sie nicht sagen.

Ein paar Datenpunkte: In Ruby gibt alles einen Wert zurück. Was gibt def zurück? Es immer gibt nil zurück, kein Method Objekt. Und define_method? Es gibt eine Proc, aber keine Method (noch eine UnboundMethod) zurück. [Hinweis: In Rubinius gibt def den kompilierten Bytecode der Methode zurück, aber immer noch kein Method Objekt.]

Wenn Sie den vierten und fünften Abschnitt von Abschnitt 6.1 der Ruby Language Specification (Zeilen 29-34 und 1-5 auf den Seiten 5 und 6) betrachten, können Sie deutlich sehen, dass zwischen Methoden unterschieden wird und Objekte. Und wenn Sie sich die Spezifikation der eingebauten Klassen ansehen, werden Sie feststellen, dass weder Method noch UnboundMethod drin sind, noch ist Object#method. IOW: Sie können einen vollkommen standardkonformen Ruby-Interpreter erstellen, in dem die Methoden keine Objekte sind.

Nun, Blöcke OTOH definitiv sind nicht Objekte. Es gibt viele Möglichkeiten, KonstrukteProc Objekte aus Blöcken, die dann das gleiche Verhalten wie der ursprüngliche Block (lambda, proc, Proc.new, die & Sigil) haben, aber Blöcke selbst sind keine Objekte.

Denken Sie darüber nach: Sie können eine Zeichenfolge an File.new übergeben, um ein Dateiobjekt zu erstellen, aber das macht keine Zeichenfolge zu einer Datei. Sie können einen Block an Proc.new übergeben, um ein proc-Objekt zu erstellen, aber das macht einen Block nicht zu einem proc.

+0

Nur für die Referenz: http://stackoverflow.com/questions/4294485/how-do-i-reference-a-function-in-ruby/4294660#4294660 –

+2

Nicht sarkastisch klingen wollen, aber was ist ein Block? Ist es nur ein Stück Text in einer .rb-Datei? –

+0

Jörg stellte klar, dass Ruby-Methoden keine Objekte in einer späteren StackOverflow-Frage sind, auf die @ MladenJablanović verweist. Hier ist das Zitat: "Beachten Sie jedoch, dass sowohl die Methode als auch die UnboundMethode Wrapper um die Methode sind, nicht die Methode selbst. Methoden sind keine Objekte in Ruby. (Im Gegensatz zu dem, was ich in anderen Antworten geschrieben habe, BTW. Ich brauche wirklich zurückgehen und diese reparieren.) " – Powers

2

Objekte und Methoden sind nicht gleich, auch wenn der Rückgabewert für die Methoden ein Objekt und nicht Null ist. Objekte befinden sich auf dem Heap, außer in einer Methode, Lambda oder Proc-Bereich und die Methode selbst lebt auf dem Stapel und hat eine Adresse nach der Interpretation zugewiesen, während statische und Klassenobjekte auf dem Heap zugeordnet sind. Ruby verwendet C weiterhin, um es zu interpretieren und an die VALUE-Struktur zu übergeben.

+2

Aus Rubins Perspektive sind Methoden Objekte. Die Implementierungsdetails sind nicht wichtig. Eine Methode kann wie jedes andere Objekt adressiert und übergeben werden. Procs sind auch Objekte (und Blöcke sind nur eine syntaktische Art, einen Proc/Lambda zu erzeugen). – simonmenke

0

Da Klammern in Ruby optional sind, werden Methodenobjekte generell in dem Sinne "versteckt", dass Sie das Methodenobjekt explizit über die Methode method abrufen müssen. Wenn Sie sich jedoch bemühen, ein Methodenobjekt zu erfassen, wird klar, dass es sich wie ein Objekt verhält. Seit Ruby> = 2.1 ist dies einfacher zu nutzen als je zuvor.

Zum Beispiel können Sie Ihre Methoden kennen zu verhalten sich mehr wie sie in Javascript tun (wo keine Pars das Verfahren Objekt und Pars verwendet werden, um die Methode zu nennen) wie folgt:

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 

See this gist für eine Version mit diesen Beispielen als Tests geschrieben.

JRL's answer Matz Buch zitiert sagen, dass Methoden wie Strings usw. sind, aber Methode Objekte sind real, und anders als die Pars/no-Pars, was sie wirken so ziemlich wie jeder andere Ruby-Objekt keine Objekte sind. Es ist ein duck-typed language, also würde ich sagen, dass Methoden als Objekte in meinem Buch qualifiziert.