Skip to main content
Engineering LibreTexts

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}}\)

    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).

    Browsing a class and its metaclass.
    Figure \(\PageIndex{1}\): Browsing a class and its metaclass.

    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.


    This page titled 6.5: The Instance Side and the Class Side is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.