I was wondering, if I define a new class variable, for example for the class MyClass
, is the definition going to be in MyClass
or in MyClass class
? Does MyClass class
even know about the new class variable?
2 Answers
Yes, class variables are shared with the class and the metaclass. They are also shared with all subclasses (and their metaclasses). A class variable is usually Capitalized, to convey better the idea of being shared in a scope broader than the class. You define class variables in the class (not the metaclass).
Class variables should not be confused with class instance variables, which are instance variables defined at the metaclass level, i.e., instance variables of the class object. This notion is somewhat obscure despite its simplicity (or because of it): instance variables are always defined in the class to define the shape (slots) of its instances. Thus, if we apply this definition to the metaclass, which is the class of the class, an instance variable defined here defines the shape of its instances, of which there is (usually) only one, the class.
Going back to class variables, you define them in the class (inst side) and initialize them in the metaclass (i.e., class side). Remember that these are (partial) globals in the sense that will be shared among instances, subinstances, subclasses and metaclasses and so they must be handled with the usual care we treat globals.
One more clarification
When we say that instance variables are shared among instances and subinstances, we mean their names (and positions in memory of the object slots); we don't mean their values (contents of said slots). Thus, two instances of the class C
will share the name, say color
, if the class defines the ivar color
, but their values at each of the instances will be independent. In other words, what it is shared is the name, not the value.
With class variables what is shared is both the name and the value. It is actually the Association
object, for example Theme -> aTheme
, what's shared. In consequence, any modification to the value of a class variable affects all its references. This is not the case with class instance variables because they are nothing but instance variables, except that they shape the class and its subclasses, rather than regular instances and subinstances.
For more information on Smalltalk variables see https://stackoverflow.com/a/42460583/4081336

- 14,495
- 4
- 29
- 51
-
So if meta classes weren't singletons, that would mean that class variables would be shared between all instances of the meta class? – EL_9 Jan 20 '21 at 17:22
-
@EL_9 it's not obvious, see why in my answer. It depends how classPool is defined in Metaclass. If it would have several instances (that means several classes sharing the same Metaclass), then we could eventually define the classPool as the union of classPools of all instances. We would need to define how to resolve conflicts, the metaclass also inherits from its instance superclass metaclass, which would then complicate things quite a lot with multiple instances, etc... – aka.nice Jan 20 '21 at 17:30
-
... or we would have to attach the classPool to the Metaclass rather than to the class, and reverse the relation, in Metaclass `^classPool "an instance variable"`, in Class `^self class classPool` – aka.nice Jan 20 '21 at 17:42
Just as a complement to Leandro's answer, here is the main Squeak implementation specific method that explains the sharing of class variables between instance side (class) and class side (metaclass):
Metaclass>>classPool
"Answer the dictionary of class variables."
^thisClass classPool
where thisClass
is the unique instance of the Metaclass, that is the class itself...
There are high chances though to find similar implementation in most Smalltalk dialects.
The compiler will first try to resolve the variable as a method/block temporary (including methd/block parameters), then instance variables, then shared variables.
The classPool method is sent by the compiler in this last phase.
A Leandro did explain, the compiler either resolve the binding just as an offset that will be directly transcripted in the bytecode in case of instance variable slot or method temporary variable, or as a kind of Association for the shared variable case, this association being generally added to the CompiledMethod literals and effectively shared among all methods dealing with this variable (all methods points to the same Assocation object which is effectively shared).
The compiler part is much more dialect specific, in Squeak, it's this method which is used for resolving the binding of shared variables:
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
This is to remind you that one of the most interesting part of Smalltalk is that you can dig into the implementation from within the IDE, Smalltalk is essentially written in Smalltalk!

- 9,100
- 1
- 28
- 40