6.5: The Instance Side and the Class Side
- Page ID
- 39602
\( \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}\)Since classes are objects, they can have their own instance variables and their own methods. We call these class instance variables and class methods, but they are really no different from ordinary instance variables and methods: They simply operate on different objects (classes in this case). An instance variable describes instance state and a method describes instance behavior. Similarly, class instance variables are just instance variables defined by a metaclass (and describe the state of classes - instances of metaclasses), and class methods are just methods defined by a metaclass (and that will be executed on classes).
A class and its metaclass are two separate classes, even though the former is an instance of the latter. However, this is largely irrelevant to you as a programmer: you are concerned with defining the behavior of your objects and the classes that create them.
For this reason, the browser helps you to browse both class and metaclass as if they were a single thing with two ”sides”: the instance side and the class side, as shown in Figure \(\PageIndex{1}\). By default, when you select a class in the browser, you’re browsing the instance side (i.e., the methods that are executed when messages are sent to an instance of Color
). Clicking on the Class side button switches you over to the class side (the methods that will be executed when messages are sent to the class Color
itself).

For example, Color blue
sends the message blue
to the class Color
. You will therefore find the method blue
defined on the class side of Color
, not on the instance side.
"Class-side method blue (convenient instance creation method)" aColor := Color blue. >>> Color blue "Color instances are self-evaluating"
"Instance-side accessor method red (returns the red RGB value)" Color blue red >>> 0.0
"Instance-side accessor method blue (returns the blue RGB value)" Color blue blue >>> 1.0
You define a class by filling in the template proposed on the instance side. When you accept this template, the system creates not just the class that you defined, but also the corresponding metaclass (which you can then edit by clicking on the Class side button). The only part of the metaclass creation template that makes sense for you to edit directly is the list of the metaclass’s instance variable names.
Once a class has been created, browsing its instance side (Class side unchecked) lets you edit and browse the methods that will be possessed by instances of that class (and of its subclasses).
Class methods
Class methods can be quite useful; browse Color class
for some good examples. You will see that there are two kinds of methods defined on a class: instance creation methods, like Color class>>blue
, and those that perform a utility function, like Color class>>wheel:
. This is typical, although you will occasionally find class methods used in other ways.
It is convenient to place utility methods on the class side because they can be executed without having to create any additional objects first. Indeed, many of them will contain a comment designed to make it easy to execute them.
Browse method Color class>>wheel:
, double-click just at the beginning of the comment "(Color wheel: 12) inspect
" and press CMD-d
. You will see the effect of executing this method.
For those familiar with Java and C++, class methods may seem similar to static methods. However, the uniformity of the Pharo object model (where classes are just regular objects) means that they are somewhat different: whereas Java static methods are really just statically-resolved procedures, Pharo class methods are dynamically-dispatched methods. This means that inheritance, overriding and super-sends work for class methods in Pharo, whereas they don’t work for static methods in Java.
Class instance variables
With ordinary instance variables, all the instances of a class have the same set of variable names (though each instance has its own private set of values), and the instances of its subclasses inherit those names. The story is exactly the same with class instance variables: each class has its own private class instance variables. A subclass will inherit those class instance variables, but the subclass will have its own private copies of those variables. Just as objects don’t share instance variables, neither do classes and their subclasses share class instance variables.
For example, you could use a class instance variable called count
to keep track of how many instances you create of a given class. However, any subclass would have its own count
variable, so subclass instances would be counted separately.
Example: Class instance variables and subclasses
Suppose we define the class Dog
, and its subclass Hyena
. Suppose that we add a count
class instance variable to the class Dog
(i.e. we define it on the metaclass Dog class
). Hyena
will naturally inherit the class instance variable count
from Dog
.
Object subclass: #Dog instanceVariableNames: '' classVariableNames: '' package: 'PBE-CIV'
Dog class instanceVariableNames: 'count'
Dog subclass: #Hyena instanceVariableNames: '' classVariableNames: '' package: 'PBE-CIV'
Now suppose we define class methods for Dog
to initialize its count
to 0, and to increment it when new instances are created:
Dog class >> initialize count := 0.
Dog class >> new count := count +1. ^ super new
Dog class >> count ^ count
Now when we create a new Dog
, the count
value of the class Dog
is incremented, and so is that of the class Hyena
(but the hyenas are counted separately).
Note
Notice the use of initialize
on the classes, in the following code. In Pharo, when you instantiate an object such as Dog new
, initialize
is called automatically as part of the new message send (you can see for yourself by browsing Behavior>>new
). But with classes, simply defining them does not automatically call initialize
, and so we have to call it explicitly here. By default class initialize
methods are automatically executed only when classes are loaded. See also the discussion about lazy initialization, below.
Dog initialize. Hyena initialize. Dog count >>> 0 Hyena count >>> 0
| aDog | aDog := Dog new. Dog count >>> 1 "Incremented" Hyena count >>> 0 "Still the same"
Class instance variables are private to a class in exactly the same way that instance variables are private to an instance. Since classes and their instances are different objects, this has the following consequences:
A class does not have access to the instance variables of its own instances. So, the class Color
does not have access to the variables of an object instantiated from it, aColorRed
. In other words, just because a class was used to create an instance (using new
or a helper instance creation method like Color red
), it doesn’t give the class any special direct access to that instance’s variables. The class instead has to go through the accessor methods (a public interface) just like any other object.
The reverse is also true: an instance of a class does not have access to the class instance variables of its class. In our example above, aDog
(an individual instance) does not have direct access to the count
variable of the Dog
class (except, again, through an accessor method).
Important
A class does not have access to the instance variables of its own instances. An instance of a class does not have access to the class instance variables of its class.
For this reason, instance initialization methods must always be defined on the instance side, the class side has no access to instance variables, and so cannot initialize them! All that the class can do is to send initialization messages, using accessors, to newly created instances.
Java has nothing equivalent to class instance variables. Java and C++ static variables are more like Pharo class variables (discussed in Section 6.9), since in those languages all of the subclasses and all of their instances share the same static variable.
Example: Defining a Singleton
The Singleton pattern provides a typical example of the use of class instance variables and class methods. Imagine that we would like to implement a class WebServer
, and to use the Singleton pattern to ensure that it has only one instance.
We define the class WebServer
as follow.
Object subclass: #WebServer instanceVariableNames: 'sessions' classVariableNames: '' package: 'Web'
Then, clicking on the Class side button, we add the (class) instance variable uniqueInstance
.
WebServer class instanceVariableNames: 'uniqueInstance'
As a result, the class WebServer class
will have a new instance variable (in addition to the variables that it inherits from Behavior
, such as superclass
and methodDict
). It means that the value of this extra instance variable will describe the instance of the class WebServer class
i.e. the class WebServer
.
Object class allInstVarNames >>> "#('superclass' 'methodDict' 'format' 'layout' 'instanceVariables' 'organization' 'subclasses' 'name' 'classPool' 'sharedPools' 'environment' 'category' 'traitComposition' 'localSelectors')" WebServer class allInstVarNames >>>"#('superclass' 'methodDict' 'format' 'layout' 'instanceVariables' 'organization' 'subclasses' 'name' 'classPool' 'sharedPools' 'environment' 'category' 'traitComposition' 'localSelectors' #uniqueInstance)"
We can now define a class method named uniqueInstance
, as shown below. This method first checks whether uniqueInstance
has been initialized. If it has not, the method creates an instance and assigns it to the class instance variable uniqueInstance
. Finally the value of uniqueInstance
is returned. Since uniqueInstance
is a class instance variable, this method can directly access it.
WebServer class >> uniqueInstance uniqueInstance ifNil: [ uniqueInstance := self new ]. ^ uniqueInstance
The first time that WebServer uniqueInstance
is executed, an instance of the class WebServer
will be created and assigned to the uniqueInstance
variable. The next time, the previously created instance will be returned instead of creating a new one. (This pattern, checking if a variable is nil in an accessor method, and initializing its value if it is nil, is called lazy initialization).
Note that the instance creation code in the code above is written as self new
and not as WebServer new
. What is the difference? Since the uniqueInstance
method is defined in WebServer class
, you might think that there is no difference. And indeed, until someone creates a subclass of WebServer
, they are the same. But suppose that ReliableWebServer
is a subclass of WebServer
, and inherits the uniqueInstance
method. We would clearly expect ReliableWebServer uniqueInstance
to answer a ReliableWebServer
. Using self
ensures that this will happen, since self
will be bound to the respective receiver, here the classes WebServer
and ReliableWebServer
. Note also that WebServer
and ReliableWebServer
will each have a different value for their uniqueInstance
instance variable.
A note on lazy initialization. Do not over-use the lazy initialization pattern. The setting of initial values for instances of objects generally belongs in the initialize
method. Putting initialization calls only in initialize helps from a readability perspective – you don’t have to hunt through all the accessor methods to see what the initial values are. Although it may be tempting to instead initialize instance variables in their respective accessor methods (using ifNil:
checks), avoid this unless you have a good reason.
For example, in our uniqueInstance
method above, we used lazy initialization because users won’t typically expect to call WebServer initialize
. Instead, they expect the class to be ”ready” to return new unique instances. Because of this, lazy initialization makes sense. Similarly, if a variable is expensive to initialize (opening a database connection or a network socket, for example), you will sometimes choose to delay that initialization until you actually need it.