2012-05-09 6 views
12

Ich verstehe, dass alle Klassen in Ruby Instanzen der Klasse Metaklasse sind. Und diese "regulären" Objekte sind Instanzen dieser Klassen (die Instanzen der Metaklassenklasse).Ruby Metaklasse Verwirrung

Aber ich frage mich, ich meine Klassen sind Wurzel von Objekten, Klassen sind selbst Instanzen der Klasse (genannt Metaklasse, weil seine Instanzen Klassen sind). Ich habe in einigen Blogs ein Überschreiben der Methode new der Klasse Class gesehen.

So verhält sich Klasse als eine Klasse, aber ihre Instanzen sind Klassen. Es scheint also, dass wir einen Kreis haben, es sieht nach Klasse aus. Klasse ist eine Instanz von sich selbst.

Ich vermisse hier eindeutig einen Punkt. Was ist der Ursprung der Klassenklasse?

Hier ist ein Beispiel, das ich ist verwirrend:

class Class 
    def new 
    #something 
    end 
end 

Aber Stichwort class impliziert eine Instanz der Klasse Klasse. Wie funktioniert das?

+4

'Class.class # => Class' – Flexoid

+5

Es ist Schildkröten den ganzen Weg hinunter! –

+0

Siehe auch [Die Paradox Verwirrung der Klasse/Objekt] (http://stackoverflow.com/questions/7675774/the-class-object-paradox-confusion). –

Antwort

28

wie tun, um diese Arbeit

Ganz einfach: es funktioniert nicht. Jedenfalls nicht in Ruby.

Genau wie in den meisten anderen Sprachen gibt es einige Kerneinheiten, von denen einfach angenommen wird, dass sie existieren. Sie fallen vom Himmel, materialisieren aus dünner Luft, erscheinen magisch.

In Ruby, einige dieser magischen Dinge sind:

  • Object keine übergeordnete Klasse haben, aber man kann nicht eine Klasse ohne übergeordnete Klasse, die implizite direkte Ober definieren ist immer Object. [Anmerkung: Es kann Implementierungs-definierte Superklassen von Object geben, aber schließlich wird es einen geben, der keine Superklasse hat.]
  • Object ist eine Instanz Class, die eine Unterklasse von Object (was die indirekt Object bedeutet eine Instanz von Object selbst) ist
  • Class eine Unterklasse von Module ist, die eine Instanz von Class ist
  • Class ist eine Instanz von Class

Keines dieser Dinge kann in Ruby erklärt werden.

BasicObject, Object, Module und Class alle müssen in die Existenz zugleich springen, weil sie zirkuläre Abhängigkeiten haben.

Nur weil diese Beziehung nicht in Ruby-Code ausgedrückt werden kann, bedeutet das nicht, dass die Ruby Language Specification nicht sagen kann, dass es so sein muss. Es liegt am Implementierer, einen Weg zu finden, dies zu tun. Schließlich hat die Ruby-Implementierung Zugriff auf die Objekte, die Sie als Programmierer nicht haben.

Zum Beispiel könnte die Ruby-Implementierung ersten BasicObject schaffen, sowohl seine superclass Zeiger und seine class Zeiger auf null Einstellung.

Dann schafft es Object, seine superclass Zeiger auf BasicObject und seine class Zeiger auf null Einstellung.

Als nächstes erzeugt es Module, seine superclass Zeiger auf Object und seine class Zeiger auf null Einstellung.

Schließlich schafft es Class, seine superclass Zeiger auf Module und seine class Zeiger auf null Einstellung.

Jetzt können wir BasicObject 's, Object' s, Module 's, und Class' s class Zeiger überschreiben zu Class-zu-Punkt, und wir sind fertig.

Dies ist leicht von außerhalb des Systems zu tun, es sieht einfach komisch von innen.

Sobald sie tun existieren, ist es jedoch durchaus möglich, den Großteil ihres Verhaltens in einfachen Ruby zu implementieren. Sie brauchen nur sehr Barebone-Versionen dieser Klassen, dank der offenen Klassen von Ruby können Sie fehlende Funktionen zu einem späteren Zeitpunkt hinzufügen.

In Ihrem Beispiel wird die class Class nicht Erstellen eine neue Klasse Class genannt, wird die bestehenden Klasse Wiedereröffnung Class, die wir von der Laufzeitumgebung gegeben wurde.

So ist es durchaus möglich, das Standardverhalten von Class#new im Klar Ruby zu erklären:

class Class 
    def new(*args, &block) 
    obj = allocate # another magic thing that cannot be explained in Ruby 
    obj.initialize(*args, &block) 
    return obj 
    end 
end 

[Anmerkung:. Tatsächlich, initialize privat ist, so dass Sie obj.send(:initialize, *args, &block) verwenden müssen, die Zugriffsbeschränkung zu umgehen]

BTW: Class#allocate ist ein weiteres dieser magischen Dinge. Es weist ein neues leeres Objekt in Rubys Objektraum zu, was in Ruby nicht möglich ist. Class#allocate muss also auch vom Laufzeitsystem bereitgestellt werden.

+3

Ich denke du meinst "' BasicObject's Superklasse ist 'nil'", da 'Object' die Superklasse' BasicObject' ist. –

+2

@AndrewMarshall: Das ist neu in 1.9. 1.8 hat nur "Object" ohne "BasicObject". –

+2

@HolgerJust True, aber 1.8 ist fast am Ende des Lebens, und wenn der Fragesteller nicht angibt, nehme ich die neueste Version von Ruby an. –

1

Obwohl es ein bisschen veraltet ist, kann this article by _why helfen, das Verhalten zu verstehen. In Paolo Perruttas Metaprogramming Ruby finden Sie einen noch tieferen Einblick in das Thema.

+0

Worum es hier geht, hat nichts damit zu tun, dass Parello das Wort "metaclass" verwendet. Worüber er spricht, ist die Singleton-Klasse oder, umgangssprachlich, die Eigenklasse. – Chuck

2

Ja, Klasse ist ein Beispiel für sich. Es ist eine Unterklasse von Module, die auch eine Instanz der Klasse ist, und Modul ist eine Unterklasse von Object, die auch eine Instanz von Class ist. Es ist in der Tat ziemlich zirkulär - aber das ist Teil der Kernsprache, nicht etwas in einer Bibliothek. Die Ruby-Laufzeit selbst hat nicht die gleichen Grenzen wie Sie oder ich, wenn wir Ruby-Code schreiben.

Ich habe noch nie das Wort "Metaklasse" gehört, um über Klasse zu sprechen. Es wird nicht viel in Ruby verwendet, aber wenn es ist, ist es normalerweise ein Synonym für das, was offiziell eine "Singleton-Klasse eines Objekts" genannt wird, was ein noch verwirrenderes Thema als das Dreieck der Objekt-Modul-Klasse ist.

+1

Tatsächlich kann die Klasse gemäß der allgemeinen Definition als Metaklasse bezeichnet werden. Aber die Welt Metaklasse habe ich irrtümlich für andere Dinge von vielen Rubinisten benutzt. Diese Metaklassen sind jedoch gemäß allgemeiner Definition schwache Metaklassen. Wenn ich mich gut erinnere, sind die Dinge, die in Ruby oft als Metaklasse bezeichnet werden, Singles, die die Klassenmethoden enthalten. Ich habe mehrere Artikel darüber gelesen und gesagt, dass das Wort Metaklasse irrtümlicherweise verwendet wurde, und sie beschuldigten das Rails Team in diesem Punkt. Danke an alle. – Perello

2

Es gibt eine Meta-Zirkularität, die durch den Link "twist" gegeben ist. Es ist der eingebaute Superklassenlink von der Eigenklasse des Stamms zur Klasse Class. Dies kann durch

BasicObject.singleton_class.superclass == Class 

Ein Hinweis zum Verständnis der .class Karte Diese Karte ist zu sehen, wie sich aus den Eigenklasse und Ober Links abgeleitet ausgedrückt werden: für ein Objekt x ist x.class die erste Klasse in der übergeordneten Klasse Kette von x ‚s Eigenklasse. Dies kann durch

x.class == x.eigenclass.superclass(n) 

ausgedrückt werden, wobei eigenclass ein „konzeptuellen alias“ von singleton_class (resistent gegen Probleme mit Sofortwerten), bedeutet y.superclass(i)i -te Oberklasse von y und n ist am kleinsten, so dass x.eigenclass.superclass(n) eine Klasse . Gleichermaßen werden Eigenklassen in der Superklassenkette von x.eigenclass übersprungen (siehe rb_class_real, was auch zeigt, dass in der MRI sogar superclass Links indirekt implementiert werden – sie entstehen durch Überspringen von " iClasses"). Dies führt dazu, dass der class jeder Klasse (sowie jeder Eigenklasse) ständig die Class Klasse ist.

Ein Bild wird von this diagram zur Verfügung gestellt.

die Metaklasse Verwirrung besteht aus 2 Hauptquellen:

  • Smalltalk. Das Smalltalk-80-Objektmodell enthält konzeptionelle Inkonsistenzen, die durch das Ruby-Objektmodell behoben werden. Darüber hinaus verwendet Smalltalk Literatur Dialektik in der Terminologie, die leider in der Ruby-Literatur nicht ausreichend behoben wurde.

  • Die Definition von Metaklasse. Gegenwärtig besagt die Definition, dass Metaklassen Klassen der Klassen sind. Für so genannte " implizite Metaklassen" (der Fall von Ruby und Smalltalk-80) wäre eine viel passendere Definition die von Meta-Objekten von Klassen.