Skip to main content
Engineering LibreTexts

5.7: Shared Variables

  • Page ID
    37702
  • \( \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}}\)

    Now we will look at an aspect of Smalltalk that is not so easily covered by our five rules: shared variables.

    Smalltalk provides three kinds of shared variables: (1) globally shared variables; (2) variables shared between instances and classes (class variables), and (3) variables shared amongst a group of classes (pool variables). 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 Squeak, 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 Transcript names an instance of TranscriptStream, a stream that writes to a scrolling window. The following code displays some information and then goes to the next line in the Transcript.

    Transcript show: 'Squeak is fun and powerful' ; cr
    

    Before you do it, open a transcript by dragging one from the Tools flap.

    Hint

    Writing to the Transcript is slow, especially when the transcript window is open. So, if you experience some sluggishness and are writing to the Transcript, think about collapsing it.

    Other useful global variables

    • Smalltalk is the instance of SystemDictionary that defines all of the globals — including Smalltalk itself. The keys to this dictionary are the symbols that name the global objects in Smalltalk code. So, for example,

      Smalltalk at: #Boolean → Boolean
      

      Since Smalltalk is itself a global variable,

      Smalltalk at: #Smalltalk → a SystemDictionary(lots of globals)}
      

      and

      (Smalltalk at: #Smalltalk) == Smalltalk → true
      
    • Sensor is an instance of EventSensor, and represents input to Squeak. For example, Sensor keyboard answers the next character input on the keyboard, and Sensor leftShiftDown answers true if the left shift key is being held down, while Sensor mousePoint answers a Point indicating the current mouse location.

    • 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 — it 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!

    • SystemOrganization is an instance of SystemOrganizer: it records the organization of classes into packages. More precisely, it categorizes the names of classes, so

      SystemOrganization categoryOfElement: #Magnitude → #'Kernel-Numbers'

    Current 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 Squeak 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 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 at: #AGlobalName put: nil. To remove it, execute Smalltalk 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.

    Instance and class methods accessing different variables.
    Figure \(\PageIndex{1}\): Instance and class methods accessing different variables.

    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: ColorNames 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 (class 5.20).

    Code \(\PageIndex{1}\) (Squeak): Color and Its Class Variables

    Object subclass: #Color
        instanceVariableNames: 'rgb cachedDepth cachedBitPattern'
        classVariableNames: 'Black Blue BlueShift Brown CachedColormaps ColorChart
        ColorNames ComponentMask ComponentMax Cyan DarkGray Gray
        GrayToIndexMap Green GreenShift HalfComponentMask HighLightBitmaps
        IndexedColors LightBlue LightBrown LightCyan LightGray LightGreen
        LightMagenta LightOrange LightRed LightYellow Magenta MaskingMap Orange
        PaleBlue PaleBuff PaleGreen PaleMagenta PaleOrange PalePeach PaleRed
        PaleTan PaleYellow PureBlue PureCyan PureGreen PureMagenta PureRed
        PureYellow RandomStream Red RedShift TranslucentPatterns Transparent
        VeryDarkGray VeryLightGray VeryPaleRed VeryVeryDarkGray
        VeryVeryLightGray White Yellow'
        poolDictionaries: ''
        category: 'Graphics-Primitives'
    

    The class variable ColorNames is an array containing the name of frequently-used colors. This array is shared by all the instances of Color and its subclass TranslucentColor. It is accessible from all the instance and class methods.

    ColorNames is initialized once in Color class»initializeNames, but it is accessed from instances of Color. The method Color»name uses the variable to find the name of a color. Since most colors do not have names, it was thought inappropriate to add an instance variable name to every color.

    Class initialization

    The presence of class variables raises the question: how do we initialize them? One solution is lazy initialization. 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.

    Code \(\PageIndex{2}\) (Squeak): Color class»colorNames

    Color class»colorNames
        ColorNames ifNil: [self initializeNames].
        ↑ ColorNames
    

    Another solution is to override the class method initialize.

    Code \(\PageIndex{3}\) (Squeak): Color class»initialize

    Color class»initialize
        ...
        self initializeNames
    

    If you adopt this solution, you need to remember to invoke the initialize method after you define it, e.g., by evaluating Color initialize. Although class side initialize methods are executed automatically when code is loaded into memory, 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.

    Code \(\PageIndex{4}\) (Squeak): Pool Dictionaries in the Text Class

    ArrayedCollection subclass: #Text
        instanceVariableNames: 'string runs'
        classVariableNames: ''
        poolDictionaries: ’TextConstants’
        category: '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.

    Code \(\PageIndex{5}\) (Squeak): Text»testCR

    Text»testCR
        ↑ CR == Character cr
    

    Once again, we recommend that you avoid the use of pool variables and pool dictionaries.


    This page titled 5.7: Shared Variables is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by Andrew P. Black, Stéphane Ducasse, Oscar Nierstrasz, Damien Pollet via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.