Où sont définies les variables de classe dans Smalltalk?

Jan 19 2021

Je me demandais si je définissais une nouvelle variable de classe, par exemple pour la classe MyClass, la définition sera-t-elle dans MyClassou dans MyClass class? Connaît MyClass class- il même la nouvelle variable de classe?

Réponses

5 LeandroCaniglia Jan 20 2021 at 00:36

Oui, les variables de classe sont partagées avec la classe et la métaclasse. Ils sont également partagés avec toutes les sous-classes (et leurs métaclasses). Une variable de classe est généralement en majuscule, pour mieux véhiculer l'idée d'être partagée dans une portée plus large que la classe. Vous définissez des variables de classe dans la classe (pas la métaclasse).

Les variables de classe ne doivent pas être confondues avec les variables d'instance de classe, qui sont des variables d'instance définies au niveau de la métaclasse, c'est-à-dire des variables d'instance de l'objet de classe. Cette notion est quelque peu obscure malgré sa simplicité (ou à cause d'elle): les variables d'instance sont toujours définies dans la classe pour définir la forme (slots) de ses instances . Ainsi, si on applique cette définition à la métaclasse, qui est la classe de la classe, une variable d'instance définie ici définit la forme de ses instances, dont il n'y a (généralement) qu'une seule, la classe.

Pour en revenir aux variables de classe, vous les définissez dans la classe (côté inst) et vous les initialisez dans la métaclasse (c'est-à-dire côté classe). Rappelez-vous qu'il s'agit de globaux (partiels) dans le sens qui seront partagés entre les instances, les sous-substances, les sous-classes et les métaclasses et qu'ils doivent donc être traités avec le soin habituel que nous traitons les globaux.


Encore une clarification

Lorsque nous disons que les variables d'instance sont partagées entre les instances et les sous-instances, nous entendons leurs noms (et leurs positions dans la mémoire des emplacements d'objet); nous ne parlons pas de leurs valeurs (contenu desdits emplacements). Ainsi, deux instances de la classe Cpartageront le nom, disons color, si la classe définit l'ivar color, mais leurs valeurs à chacune des instances seront indépendantes. En d'autres termes, ce qui est partagé est le nom, pas la valeur.

Avec les variables de classe, ce qui est partagé est à la fois le nom et la valeur. C'est en fait l' Associationobjet, par exemple Theme -> aTheme, ce qui est partagé. En conséquence, toute modification de la valeur d'une variable de classe affecte toutes ses références. Ce n'est pas le cas des variables d'instance de classe car elles ne sont rien d'autre que des variables d'instance, sauf qu'elles façonnent la classe et ses sous-classes, plutôt que des instances et des sous-instances régulières.


Pour plus d'informations sur les variables Smalltalk, voir https://stackoverflow.com/a/42460583/4081336

2 aka.nice Jan 20 2021 at 23:59

En complément de la réponse de Leandro, voici la principale méthode spécifique à l'implémentation de Squeak qui explique le partage des variables de classe entre le côté instance (classe) et le côté classe (métaclasse):

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

    ^thisClass classPool

thisClassest l'instance unique de la métaclasse, c'est-à-dire la classe elle-même ...

Il y a cependant de fortes chances de trouver une implémentation similaire dans la plupart des dialectes Smalltalk.

Le compilateur essaiera d'abord de résoudre la variable en tant que méthode / bloc temporaire (y compris les paramètres methd / block), puis les variables d'instance, puis les variables partagées.

La méthode classPool est envoyée par le compilateur dans cette dernière phase.

Un Leandro a bien expliqué, le compilateur résout la liaison soit simplement comme un offset qui sera directement transcrit dans le bytecode en cas de variable d'instance slot ou de méthode variable temporaire, soit comme une sorte d'association pour le cas de variable partagée, cette association étant généralement ajoutée aux littéraux CompiledMethod et effectivement partagée entre toutes les méthodes traitant cette variable (toutes les méthodes pointent vers le même objet Assocation qui est effectivement partagé).

La partie compilateur est beaucoup plus spécifique au dialecte, dans Squeak, c'est cette méthode qui est utilisée pour résoudre la liaison des variables partagées:

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

Ceci est pour vous rappeler que l'une des parties les plus intéressantes de Smalltalk est que vous pouvez creuser dans l'implémentation depuis l'EDI, Smalltalk est essentiellement écrit en Smalltalk!