6.9: Shared Variables
- Page ID
- 40127
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)
( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\id}{\mathrm{id}}\)
\( \newcommand{\Span}{\mathrm{span}}\)
\( \newcommand{\kernel}{\mathrm{null}\,}\)
\( \newcommand{\range}{\mathrm{range}\,}\)
\( \newcommand{\RealPart}{\mathrm{Re}}\)
\( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)
\( \newcommand{\Argument}{\mathrm{Arg}}\)
\( \newcommand{\norm}[1]{\| #1 \|}\)
\( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)
\( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)
\( \newcommand{\vectorA}[1]{\vec{#1}} % arrow\)
\( \newcommand{\vectorAt}[1]{\vec{\text{#1}}} % arrow\)
\( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vectorC}[1]{\textbf{#1}} \)
\( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)
\( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)
\( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)
\( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)
\( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)
\(\newcommand{\avec}{\mathbf a}\) \(\newcommand{\bvec}{\mathbf b}\) \(\newcommand{\cvec}{\mathbf c}\) \(\newcommand{\dvec}{\mathbf d}\) \(\newcommand{\dtil}{\widetilde{\mathbf d}}\) \(\newcommand{\evec}{\mathbf e}\) \(\newcommand{\fvec}{\mathbf f}\) \(\newcommand{\nvec}{\mathbf n}\) \(\newcommand{\pvec}{\mathbf p}\) \(\newcommand{\qvec}{\mathbf q}\) \(\newcommand{\svec}{\mathbf s}\) \(\newcommand{\tvec}{\mathbf t}\) \(\newcommand{\uvec}{\mathbf u}\) \(\newcommand{\vvec}{\mathbf v}\) \(\newcommand{\wvec}{\mathbf w}\) \(\newcommand{\xvec}{\mathbf x}\) \(\newcommand{\yvec}{\mathbf y}\) \(\newcommand{\zvec}{\mathbf z}\) \(\newcommand{\rvec}{\mathbf r}\) \(\newcommand{\mvec}{\mathbf m}\) \(\newcommand{\zerovec}{\mathbf 0}\) \(\newcommand{\onevec}{\mathbf 1}\) \(\newcommand{\real}{\mathbb R}\) \(\newcommand{\twovec}[2]{\left[\begin{array}{r}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\ctwovec}[2]{\left[\begin{array}{c}#1 \\ #2 \end{array}\right]}\) \(\newcommand{\threevec}[3]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\cthreevec}[3]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \end{array}\right]}\) \(\newcommand{\fourvec}[4]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\cfourvec}[4]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \end{array}\right]}\) \(\newcommand{\fivevec}[5]{\left[\begin{array}{r}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\cfivevec}[5]{\left[\begin{array}{c}#1 \\ #2 \\ #3 \\ #4 \\ #5 \\ \end{array}\right]}\) \(\newcommand{\mattwo}[4]{\left[\begin{array}{rr}#1 \amp #2 \\ #3 \amp #4 \\ \end{array}\right]}\) \(\newcommand{\laspan}[1]{\text{Span}\{#1\}}\) \(\newcommand{\bcal}{\cal B}\) \(\newcommand{\ccal}{\cal C}\) \(\newcommand{\scal}{\cal S}\) \(\newcommand{\wcal}{\cal W}\) \(\newcommand{\ecal}{\cal E}\) \(\newcommand{\coords}[2]{\left\{#1\right\}_{#2}}\) \(\newcommand{\gray}[1]{\color{gray}{#1}}\) \(\newcommand{\lgray}[1]{\color{lightgray}{#1}}\) \(\newcommand{\rank}{\operatorname{rank}}\) \(\newcommand{\row}{\text{Row}}\) \(\newcommand{\col}{\text{Col}}\) \(\renewcommand{\row}{\text{Row}}\) \(\newcommand{\nul}{\text{Nul}}\) \(\newcommand{\var}{\text{Var}}\) \(\newcommand{\corr}{\text{corr}}\) \(\newcommand{\len}[1]{\left|#1\right|}\) \(\newcommand{\bbar}{\overline{\bvec}}\) \(\newcommand{\bhat}{\widehat{\bvec}}\) \(\newcommand{\bperp}{\bvec^\perp}\) \(\newcommand{\xhat}{\widehat{\xvec}}\) \(\newcommand{\vhat}{\widehat{\vvec}}\) \(\newcommand{\uhat}{\widehat{\uvec}}\) \(\newcommand{\what}{\widehat{\wvec}}\) \(\newcommand{\Sighat}{\widehat{\Sigma}}\) \(\newcommand{\lt}{<}\) \(\newcommand{\gt}{>}\) \(\newcommand{\amp}{&}\) \(\definecolor{fillinmathshade}{gray}{0.9}\)Now we will look at an aspect of Pharo that is not so easily covered by our five rules: shared variables.
Pharo provides three kinds of shared variables:
- Globally shared variables.
- Class variables: variables shared between instances and classes. (Not to be confused with class instance variables, discussed earlier).
- Pool variables: variables shared amongst a group of classes,
The names of all of these shared variables start with a capital letter, to warn us that they are indeed shared between multiple objects.
Global variables
In Pharo, all global variables are stored in a namespace called Smalltalk
, which is implemented as an instance of the class SystemDictionary
. Global variables are accessible everywhere. Every class is named by a global variable. In addition, a few globals are used to name special or commonly useful objects.
The variable Processor
names an instance of ProcessScheduler
, the main process scheduler of Pharo.
Processor class >>> ProcessorScheduler
Other useful global variables
Smalltalk is the instance of SmalltalkImage
. It contains many functionality to manage the system. In particular it holds a reference to the main namespace Smalltalk globals
. This namespace includes Smalltalk
itself since it is a global variable. The keys to this namespace are the symbols that name the global objects in Pharo code. So, for example:
Smalltalk globals at: #Boolean >>> Boolean
Since Smalltalk
is itself a global variable:
Smalltalk globals at: #Smalltalk >>> Smalltalk (Smalltalk globals at: #Smalltalk) == Smalltalk >>> true
World is an instance of PasteUpMorph
that represents the screen. World bounds
answers a rectangle that defines the whole screen space; all Morphs on the screen are submorphs of World
.
ActiveHand is the current instance of HandMorph
, the graphical representation of the cursor. ActiveHand
’s submorphs hold anything being dragged by the mouse.
Undeclared is another dictionary, which contains all the undeclared variables. If you write a method that references an undeclared variable, the browser will normally prompt you to declare it, for example as a global or as an instance variable of the class. However, if you later delete the declaration, the code will then reference an undeclared variable. Inspecting Undeclared
can sometimes help explain strange behaviour!
Using globals in your code
The recommended practice is to strictly limit the use of global variables. It is usually better to use class instance variables or class variables, and to provide class methods to access them. Indeed, if Pharo were to be implemented from scratch today, most of the global variables that are not classes would be replaced by singletons.
The usual way to define a global is just to perform Do it
on an assignment to a capitalized but undeclared identifier. The parser will then offer to declare the global for you. If you want to define a global programmatically, just execute Smalltalk globals at: #AGlobalName put: nil
. To remove it, execute Smalltalk globals removeKey: #AGlobalName
.
Class variables
Sometimes we need to share some data amongst all the instances of a class and the class itself. This is possible using class variables. The term class variable indicates that the lifetime of the variable is the same as that of the class. However, what the term does not convey is that these variables are shared amongst all the instances of a class as well as the class itself, as shown in Figure \(\PageIndex{1}\). Indeed, a better name would have been shared variables since this expresses more clearly their role, and also warns of the danger of using them, particularly if they are modified.

In Figure \(\PageIndex{1}\) we see that rgb
and cachedDepth
are instance variables of Color
, hence only accessible to instances of Color
. We also see that superclass
, subclass
, methodDict
and so on are class instance variables, i.e., instance variables only accessible to the Color
class.
But we can also see something new: ColorRegistry
and CachedColormaps
are class variables defined for Color
. The capitalization of these variables gives us a hint that they are shared. In fact, not only may all instances of Color
access these shared variables, but also the Color
class itself, and any of its subclasses. Both instance methods and class methods can access these shared variables.
A class variable is declared in the class definition template. For example, the class Color
defines a large number of class variables to speed up color creation; its definition is shown below.
Object subclass: #Color instanceVariableNames: 'rgb cachedDepth cachedBitPattern alpha' classVariableNames: 'BlueShift CachedColormaps ColorRegistry ComponentMask GrayToIndexMap GreenShift HalfComponentMask IndexedColors MaskingMap RandomStream RedShift' package: 'Graphics-Primitives'
The class variable ColorRegistry
is an instance of IdentityDictionary
containing the frequently-used colors, referenced by name. This dictionary is shared by all the instances of Color
, as well as the class itself. It is accessible from all the instance and class methods.
Class initialization
The presence of class variables raises the question: how do we initialize them?
One solution is lazy initialization (discussed earlier in this chapter). This can be done by introducing an accessor method which, when executed, initializes the variable if it has not yet been initialized. This implies that we must use the accessor all the time and never use the class variable directly. This furthermore imposes the cost of the accessor send and the initialization test. It also arguably defeats the point of using a class variable, since in fact it is no longer shared.
Another solution is to override the class method initialize
(we’ve seen this before in the Dog
example).
Color class >> initialize ... self initializeColorRegistry. ...
If you adopt this solution, you will need to remember to invoke the initialize
method after you define it (by evaluating Color initialize
). Although class side initialize
methods are executed automatically when code is loaded into memory (from a Monticello repository, for example), they are not executed automatically when they are first typed into the browser and compiled, or when they are edited and re-compiled.
Pool variables
Pool variables are variables that are shared between several classes that may not be related by inheritance. Pool variables were originally stored in pool dictionaries; now they should be defined as class variables of dedicated classes (subclasses of SharedPool
). Our advice is to avoid them; you will need them only in rare and specific circumstances. Our goal here is therefore to explain pool variables just enough so that you can understand them when you are reading code.
A class that accesses a pool variable must mention the pool in its class definition. For example, the class Text
indicates that it is using the pool dictionary TextConstants
, which contains all the text constants such as CR
and LF
. This dictionary has a key #CR
that is bound to the value Character cr
, i.e., the carriage return character.
ArrayedCollection subclass: #Text instanceVariableNames: 'string runs' classVariableNames: '' poolDictionaries: 'TextConstants' package: 'Collections-Text'
This allows methods of the class Text
to access the keys of the dictionary in the method body directly, i.e., by using variable syntax rather than an explicit dictionary lookup. For example, we can write the following method.
Text >> testCR ^ CR == Character cr
Once again, we recommend that you avoid the use of pool variables and pool dictionaries.