Wo sind Klassenvariablen in Smalltalk definiert?

Jan 20 2021

Ich habe mich gefragt, ob ich eine neue Klassenvariable definiere, zum Beispiel für die Klasse. Wird MyClassdie Definition in MyClassoder in sein MyClass class? Weiß MyClass classüberhaupt etwas über die neue Klassenvariable?

Antworten

5 LeandroCaniglia Jan 20 2021 at 00:36

Ja, Klassenvariablen werden mit der Klasse und der Metaklasse geteilt. Sie werden auch mit allen Unterklassen (und ihren Metaklassen) geteilt. Eine Klassenvariable wird normalerweise großgeschrieben, um die Idee, in einem breiteren Bereich als der Klasse geteilt zu werden, besser zu vermitteln. Sie definieren Klassenvariablen in der Klasse (nicht in der Metaklasse).

Klassenvariablen sollten nicht mit Klasseninstanzvariablen verwechselt werden, bei denen es sich um auf Metaklassenebene definierte Instanzvariablen handelt, dh um Instanzvariablen des Klassenobjekts. Dieser Begriff ist trotz seiner Einfachheit (oder aufgrund dessen) etwas dunkel: Instanzvariablen werden immer in der Klasse definiert, um die Form (Slots) ihrer Instanzen zu definieren . Wenn wir diese Definition also auf die Metaklasse anwenden, die die Klasse der Klasse ist, definiert eine hier definierte Instanzvariable die Form ihrer Instanzen, von denen es (normalerweise) nur eine gibt, die Klasse.

Zurück zu den Klassenvariablen definieren Sie sie in der Klasse (inst-Seite) und initialisieren sie in der Metaklasse (dh auf der Klassenseite). Denken Sie daran, dass dies (Teil-) Globale in dem Sinne sind, dass sie zwischen Instanzen, Unterinstanzen, Unterklassen und Metaklassen geteilt werden. Daher müssen sie mit der üblichen Sorgfalt behandelt werden, mit der wir Globale behandeln.


Noch eine Klarstellung

Wenn wir sagen, dass Instanzvariablen von Instanzen und Subinstanzen gemeinsam genutzt werden, meinen wir deren Namen (und Positionen im Speicher der Objektsteckplätze). Wir meinen nicht ihre Werte (Inhalt dieser Slots). Somit Cteilen sich zwei Instanzen der Klasse den Namen, beispielsweise colorwenn die Klasse den ivar definiert color, aber ihre Werte an jeder der Instanzen sind unabhängig. Mit anderen Worten, was geteilt wird, ist der Name, nicht der Wert.

Bei Klassenvariablen wird sowohl der Name als auch der Wert gemeinsam genutzt. Es ist tatsächlich das AssociationObjekt, zum Beispiel Theme -> aTheme, was geteilt wird. Folglich wirkt sich jede Änderung des Werts einer Klassenvariablen auf alle ihre Referenzen aus. Dies ist bei Klasseninstanzvariablen nicht der Fall, da sie nichts anderes als Instanzvariablen sind, außer dass sie die Klasse und ihre Unterklassen formen und nicht reguläre Instanzen und Subinstanzen.


Weitere Informationen zu Smalltalk-Variablen finden Sie unter https://stackoverflow.com/a/42460583/4081336

2 aka.nice Jan 20 2021 at 23:59

Als Ergänzung zu Leandros Antwort finden Sie hier die wichtigste implementierungsspezifische Squeak-Methode, die die gemeinsame Nutzung von Klassenvariablen zwischen Instanzseite (Klasse) und Klassenseite (Metaklasse) erklärt:

Metaclass>>classPool
    "Answer the dictionary of class variables."

    ^thisClass classPool

Wo thisClassist die eindeutige Instanz der Metaklasse, das ist die Klasse selbst ...

Es besteht jedoch eine hohe Wahrscheinlichkeit, dass in den meisten Smalltalk-Dialekten eine ähnliche Implementierung gefunden wird.

Der Compiler versucht zunächst, die Variable als temporäre Methode / Block (einschließlich Methd / Block-Parameter), dann als Instanzvariablen und dann als gemeinsam genutzte Variablen aufzulösen.

Die classPool-Methode wird in dieser letzten Phase vom Compiler gesendet.

Ein Leandro hat erklärt, dass der Compiler die Bindung entweder nur als Offset auflöst, der im Fall eines Instanzvariablen-Slots oder einer temporären Methodenvariablen direkt im Bytecode transkribiert wird, oder als eine Art Assoziation für den Fall einer gemeinsam genutzten Variablen, wobei diese Assoziation im Allgemeinen ist zu den CompiledMethod-Literalen hinzugefügt und effektiv von allen Methoden gemeinsam genutzt, die sich mit dieser Variablen befassen (alle Methoden verweisen auf dasselbe Assocation-Objekt, das effektiv gemeinsam genutzt wird).

Der Compiler-Teil ist viel dialektspezifischer. In Squeak wird diese Methode zum Auflösen der Bindung gemeinsam genutzter Variablen verwendet:

class>>bindingOf: varName environment: anEnvironment
    "Answer the binding of some variable resolved in the scope of the receiver"
    | aSymbol binding |
    aSymbol := varName asSymbol.

    "First look in local classVar dictionary."
    binding := self classPool bindingOf: aSymbol.
    binding ifNotNil:[^binding].

    "Next look in local shared pools."
    self sharedPools do:[:pool | 
        binding := pool bindingOf: aSymbol.
        binding ifNotNil:[^binding].
    ].

    "Next look into superclass pools"
    superclass ifNotNil: [^ superclass bindingOf: aSymbol environment: anEnvironment].

    "No more superclass... Last look in declared environment."
    ^anEnvironment bindingOf: aSymbol

Dies soll Sie daran erinnern, dass einer der interessantesten Teile von Smalltalk darin besteht, dass Sie sich innerhalb der IDE mit der Implementierung befassen können. Smalltalk ist im Wesentlichen in Smalltalk geschrieben!