Wo sind Methoden an der Rubin obersten Ebene definiert?
Frage
Auf der obersten Ebene, Methodendefinition sollte in privaten Methoden auf Object
führen, und Tests scheinen diese heraus zu tragen:
def hello; "hello world"; end
Object.private_instance_methods.include?(:hello) #=> true
Object.new.send(:hello) #=> "hello world"
Allerdings funktioniert das folgende auch auf höchster Ebene (self.meta
die Eigenklasse von main
ist):
self.meta.private_instance_methods(false).include?(:hello) #=> true
Es scheint, dass die hello
Verfahren gleichzeitig auf die Eigenklasse des Haupt definiert sowie auf Object
. Was ist los? Beachten Sie, dass die false
Parameter private_instance_methods
schließt Superklasse Methoden aus der Methodenliste.
Lösung
Zunächst einmal dieses Verhalten und die zugrunde liegende Argumentation hat es immer gegeben; es ist nichts Neues auf 1,9. Der technische Grund, es passiert ist, weil main
speziell und anders als jedes andere Objekt behandelt. Es gibt keine Lust Erklärung zur Verfügung. Es so verhält, weil es entworfen wurde, auf diese Weise
Okay, aber warum? Was ist die Begründung für main
magisch zu sein? Da Rubys Designer Yukihiro Matsumoto denkt, dass es macht die Sprache besser um dieses Verhalten zu haben:
Sind ja, warum Top-Level-Methoden sind nicht Singleton-Methoden für dieses Objekt hergestellt, statt in als Instanzmethoden auf der Objektklasse gezogen wird selbst (Und damit auch in allen anderen Klassen das heißt mehr Namespace Verschmutzung ist, als in der Regel beabsichtigt). Dies würde nach wie vor Top-Level-Methoden ermöglichen es andere zu nennen Top-Level-Verfahren. Und wenn das Objekt der obersten Ebene wurden bezeichnet durch etwas konstant wie Main, dann könnten diese Methoden von überall aufgerufen werden mit Main.method (...).
Haben Sie wirklich Art wünschen "Main.print" überall?
Im weiteren Verlauf der Diskussion, er erklärt, dass es auf diese Weise verhält, weil er glaubt, die „Annahme natürlich ist.“
EDIT:
Als Antwort auf Ihren Kommentar, wird Ihre Frage gerichtet, warum Haupt der Eigenklasse scheint Bericht hello
als private Instanzmethode. Der Haken ist, dass keiner der Top-Level-Funktionen werden main
tatsächlich hinzugefügt, sondern direkt an Object
. Wenn mit eigenclasses arbeiten, verhält sich die instance_methods
Familie von Funktionen immer, als ob die Eigenklasse ist immer noch die ursprüngliche Klasse. Das heißt, in der Klasse definierten Methoden behandelt werden, als direkt in der Eigenklasse definiert ist. Zum Beispiel:
class Object
private
def foo
"foo"
end
end
self.send :foo # => "foo"
Object.private_instance_methods(false).include? :foo # => true
self.meta.private_instance_methods(false).include? :foo # => true
class Bar
private
def bar
"bar"
end
end
bar = Bar.new
bar.send :bar # => "bar"
Bar.private_instance_methods(false).include? :bar # => true
bar.meta.private_instance_methods(false).include? :bar # => true
Wir können eine Methode direkt an main
der Eigenklasse hinzufügen, though. Vergleichen Sie das Original Beispiel mit diesem:
def self.hello; "hello world"; end
Object.instance_methods.include? :hello # => false
self.meta.instance_methods.include? :hello # => true
Okay, aber was, wenn wir wirklich wissen wollen, dass eine gegebene Funktion auf der Eigenklasse definiert ist, nicht die ursprüngliche Klasse?
def foo; "foo"; end #Remember, this defines it in Object, not on main
def self.bar; "bar"; end #This is defined on main, not Object
foo # => "foo"
bar # => "bar"
self.singleton_methods.include? :foo # => false
self.singleton_methods.include? :bar # => true