Pattern: Lazy Initialization


Context

During Instance Initialization or Class Initialization, some instance variables can be costly to initialize (either in terms of memory or time) and, indeed, they may never be used. Is it possible to minimise this penalty?

Solution

One method is to initialize the instance variable on demand rather than during instance initialization. To do this, modify the getter accessor method, so that the variable is initialized the first time it is accessed. We know the variable is being accessed for the first time if its value is still nil.

Example

Imagine a class AudioCD which represents an audio compact disc. One of its instance variables is the list of tracks on the CD. This information can be obtained from the CD, but it is a slow operation. Using lazy initialization, we can delay querying the track information until we are actually asked for it.

tracks
	"Answer the tracks."

	tracks isNil ifTrue: [ tracks := self queryTracks ].
	^tracks

Consequences

For this technique to work, there should be no direct access of the lazy variable. Direct access to the lazy variable would bypass the 'initialize on first access' code.

The main disadvantage of lazy initialization is the time penalty associated with each access of the variable caused by the #isNil test. Another disadvantage is that the initialization code is spread around the class and occurs at an unspecified time. On occasion, this can lead to confusion.

Lazy initialization should only be used if (1a) the initialization of the instance variable would take a long time, or (1b) consume a significant amount of resources and (2) there is a good chance the variable will not be used.

Known Uses

GraphicsTool is an abstract class containing code common to Windows™GDI objects (pens, brushes etc). It defines an instance variable called handle which can be expensive to initialize and may not be required. It is therefore initialized lazily.

handle
	"Answer the receiver's handle. If unrealized then attempt to realize it first."

	handle isNil ifTrue: [self realize].
        ^handle

Note: GraphicsTool>>realize assigns to the handle instance variable.

Related Patterns