OK, was ich jetzt hier schreibe ist nichts neues und auch schon auf viel bessere Art und Weise von Why the Lucky Stiff beschrieben worden. Jedenfalls trieb mich ein Bug in Consolvix dazu, mich nochmals intensiver mit dem Thema Metaprogrammierung und dem Ruby-Objektmodell auseinanderzusetzen. Es folgen ein Paar Notizen.
- Objekte in Ruby können nur Variablen aufnehmen -- Ein Ruby-Objekt hat keine Methoden
- Objekte sind in erster Linie dies: Objekte. Erst in zweiter Linie sind sie Instanzen einer Klasse. Auch Klassen sind Objekte (ABER auf C-Quellcode-Ebene sind Object und Class zwei verschiedene Structs -- ich halte diese Information für wichtig, wenn man wirklich blicken will, warum diese Class-Objekt-Abhängigkeit keine unendliche Rekursion mit sich bringt)
- Objekt-/Instanz-Methoden befinden sich in der Klasse, von der sich das Objekt ableitet. Eine Klasse ist nicht ein statisches, abstraktes Dingda, sondern ein Singleton-Objekt. Ein Objekt, das (Klassen-)Variablen UND Methoden aufnehmen kann. Eine Klasse eben. (Und hier würde dann die Rekursion einsetzen ;-))
- Klassenmethoden befinden sich -- nein, nicht in der Klasse, die ja ein Objekt ist, sondern in der Klasse, die meistens Metaklasse genannt wird.
- Klassen vererben ihre Methoden ihren Unterklassen. Somit steht, wenn man eine Klasse um eine neue Methode bereichert, sofort sämtlichen Unterklassen und sämtlichen Instanzen der Klasse diese Methode zur Verfügung. Wenn man aber einem einzelnen Objekt an dieser Stelle eine andere Implementierung dieser Methode geben möchte, so kann man dem Objekt diese Methode über die Metaklasse dieses Objektes zur Verfügung stellen. Methoden werden zuerst in der Metaklasse dann erst in der Klassenhierachie gesucht.
- Das Konzept der Vererbung erweitert eine Klassenhierachie vertikal, während Module die Klassenhierachie horizontal erweitern -- man könne also sagen, dass das Konzept der Metaklassen die Hierachie in der tiefe erweitern -- aber das klingt gleich wieder so esotherisch...
- Metaklassen können, da diese wiederum Objekte sind, selbst auch wieder Metaklassen enthalten. Eine Veränderung der Metaklasse einer Metaklasse einer Klasse zieht jedoch keinerlei Konsequenzen für die Klasse nach sich. Außerdem ist es sehr unwahrscheinlich, dass von diesem Konzept jemals jemand Gebrauch machen wird (OK, ich werde meinen kranken Geist darauf ansetzen, in einer freien Minute etwas passendes zu finden ;-))
Folgendes ER-Diagramm hab ich nach meinem Verständnis des Sachverhaltes zusammengestellt. Wenn jemand darin einen grundlegenden Fehler entdeckt, bitte sofort melden!
Dieses Klassendiagramm habe ich nach dem ASCII-Diagram aus einem (vermutlich bekannten) Post in der Ruby-Talk-Mailingliste gebastelt. Es stellt die Abhängigkeit der Klassen und Objekte untereinander dar. Wie man sieht, erbt letztendlich alles von Object. Die Klassen mit eingeklammerten Namen sind die jeweiligen Meta-Klassen (bzw. Singleton-Klassen-Instanzen...).
Ich finde, dass das Bild etwas klarer wird, wenn man die Vererbung durch eine gerichtete Beziehung der Objekte untereinander ersetzt. super
zeigt somit immer auf das Objekt der Elternklasse während self
auf das Objekt der Singleton-Klasse zeigt.
So hat man im Wesentlichen die Abbildung des Ruby-Objektmodells auf C-Ebene vor sich: Vererbung und "magische Meta-Dingsda" sind nichts weiter als Structs, von denen einige lediglich Variablen, andere auch Methoden referenzieren können... der ganze Zauber gelüftet, aber eine Menge mehr Klarheit geschaffen :)
Zu dem ganzen ist anzumerken, dass nicht zu jedem Objekt a priori eine Singletonklasse existiert -- das würde unendlich viel Speicher erfordern. Eine Singletonklasse wird nur dann erstellt, wenn sie explizit angefordert wird, und zwar über
class Foo
# ...
end
obj = Foo.new
class << obj
# hier sind wir im Kontext der Metaklasse von obj!
end
class << Foo
# hier sind wir im Kontext der Metaklasse von Foo!
end
class Foo
class << self
class << self
# im Kontext der Metaklasse der Metaklasse von Foo ;-)
end
end
end
Alles klar? Nicht? Dann hilft nur lesen des o.g. Artikels von Why the Lucky Stiff oder sich einfach mit anderen Dingen beschäftigen...