Instance, Class & Class-Side Variables

Classic syntax for the class-side instance variable:

15.1 Three kinds of class-related state

Classic syntax for the class-side instance variable:

nobody — each instance has its own the class, all subclasses, all their instances both instance and class side Class-side instance variable nobody — Vehicle and each subclass have separate values

Object << #Vehicle
    slots: { #plate };                       "instance variables: one per instance"
    sharedVariables: { #Registry };          "class variable: ONE shared by Vehicle, subclasses, and all instances"
    package: 'Fleet'

Vehicle class << Vehicle class
    slots: { #count }                        "class-side instance variable: one per class object"
Vehicle class instanceVariableNames: 'count'

15.2 Class variables

Class variables are capitalized by convention. They are a form of global scoped to a hierarchy — use them for constants and caches shared across the hierarchy.

Vehicle class >> registry
    ^ Registry ifNil: [ Registry := OrderedCollection new ]

Vehicle >> register
    self class registry add: self

15.3 Class-side instance variables: per-class counters

With a class variable instead, all three would share one counter.

Vehicle class >> new
    count := (count ifNil: [ 0 ]) + 1.
    ^ super new

Vehicle class >> count
    ^ count ifNil: [ 0 ]

Vehicle << #Car slots: { #seats }; package: 'Fleet'.
Vehicle << #Truck slots: { #payload }; package: 'Fleet'.
Car new. Car new. Truck new.
Car count.       "→ 2"
Truck count.     "→ 1 — each class keeps its own 'count'"

15.4 Singleton with a class-side instance variable

Object << #AppConfiguration slots: { #settings }; package: 'App'.
AppConfiguration class << AppConfiguration class slots: { #uniqueInstance }.

AppConfiguration class >> uniqueInstance
    ^ uniqueInstance ifNil: [ uniqueInstance := self new ]

AppConfiguration class >> reset
    uniqueInstance := nil

15.5 Class initialization

A class-side initialize method runs once, when the class is loaded (not when instances are created). Re-run it manually after changing it:

Vehicle class >> initialize
    Registry := OrderedCollection new

Vehicle initialize.     "run it manually during development"

15.6 Lazy initialization

Vehicle >> plate
    ^ plate ifNil: [ plate := 'UNREGISTERED' ]

15.7 Slots are objects

Pharo's slots are first-class: Vehicle slots, (Vehicle slotNamed: #plate) read: aVehicle. Custom slot classes enable special behaviors (e.g., WeakSlot, PropertySlot, observable slots): slots: { #items => WeakSlot }.