Anonymous classes

TL;DR

Anonymous classes can be used to selectively change the behavior of specific objects or groups of objects for any period of time.

Understanding anonymous classes

A class is just an object that serves as a template and a repository of methods for other objects. Classes are normally named, and stored in the list of Smalltalk globals.

Smalltalk globals.
  

NB: most of these globals are classes or traits, with few exceptions.

Smalltalk globals reject: #isClassOrTrait.
  

You can also create anonymous classes , which are classes without a name. Here we create an annonymous subclass of OrderedCollection SequenceableCollection subclass: #OrderedCollection instanceVariableNames: 'array firstIndex lastIndex' classVariableNames: '' package: 'Collections-Sequenceable-Ordered' , and override the #add: method to convert its arguments to a string before adding them.

We create an instance of an ordered collection and add three numbers to it. In between the first and third numbers being added, we change the class of the collection to our anonymous collection.

anonymousCollectionInstance
	"We create an anonymous subclass of OrderedCollection with an add: method that adds the printString of an object rather than the object itself. We change the class of a collection back and forth, verifying that the number added is a string while the class is changed."

	<gtExample>
	| anonCollectionClass collection |
	anonCollectionClass := OrderedCollection newAnonymousSubclass.
	anonCollectionClass
		compile: 'add: anObject
			^ super add: anObject printString'.
	collection := OrderedCollection new.
	collection add: 1.
	self assert: collection last equals: 1.
	collection primitiveChangeClassTo: anonCollectionClass basicNew.
	collection add: 2. "The second value is converted to a String."
	self assert: collection last equals: '2'. 
	collection primitiveChangeClassTo: OrderedCollection new.

	collection add: 3.
	self assert: collection last equals: 3.
	^ collection
    

Pros

We can apply the behavioral changes selectively to specific instances of a class.

Self-sends will be captured, unlike with minimal object proxies overriding doesNotUnderstand:.

Cons

primitiveChangeClassTo: can only be used if the format of the classes of the receiver and argument are the same. This means you cannot add any new slots to the anonymous subclass.