Edit Rename Upload Download Back to Top

dictionary look-up

Bob has been trained in OO and knows that polymorphism is best. But he will argue with the idea that polymorphism fits every situation in which he wants a case statement. If you want to discriminate on values, surely it's a very heavyweight solution to create distinct classes for them just because the language lacks a case statement.

Indeed it is. Smalltalk has effective ways of coding a case-statement that wants to select on simple values. The first is to use a dictionary lookup. As an example, consider a system for managing various kinds of competition.

    Model
	subclass: #Competition
	instVars: 'prizes'
	...

    Competition>>initialize
	prizes := Dictionary new.

    Competition subclass: #LongJump

    LongJump>>initialize
	super initialize.
	self prizes
	    at: 'winner' put: 1000;
	    at:'runner up' put: 100;
	    at: 'third' put: 1.

    Competition>>prizeFor: competitor
	^self prizes
	    at: competitor place
	    ifAbsent: [0]

The dictionary acts like a case-statement, returning whatever value is keyed by the competitor's 'place' string. If no value is keyed (e.g. the competitor's 'place' string reads 'fourth'), the default value of 0 is returned. This is as easy to write as a case-statement and has the advantage that keys and values can be added, edited and deleted while the system is running.

This solution works just as well if blocks of code, not just values, must be selected. To illustrate this, consider an alternative form of the above.

    OlympicCompetition>>initialize
	self prizeCeremonies
	    at: 'winner' put: [:nation | self play: nation anthem. Medal new: 'gold'];
	    at: 'runner up' put: [:nation | self show: nation flag. Medal new: 'silver'];
	    at: 'third' put: [:nation | self show: nation name. Medal new: 'bronze'].

    OlympicCompetition>>prizeFor: competitor
	"If the competitor is in the first three places, perform the appropriate ceremony and return
	the appropriate medal.  Otherwise, give them an 'also ran' medal for competing and do nothing."

	^(self prizeCeremonies
	    at: competitor place
	    ifAbsent: [:nation | Medal new: 'also ran'])
		value: competitor nation

The implementation of the prizeFor: method supplies the competitor's nation as a parameter to whichever code block the competitor's place selects from the prizeCeremonies dictionary. It runs this code block with this parameter and returns the block's result as the result of prizeFor:.

(By the way, if we'd used integers 1, 2 and 3 to record the competitor's place, we could have used an OrderedCollection in the above instead of a Dictionary; I used a Dictionary to illustrate the general case.)

Other approaches:

(Written by Niall Ross as part of Smalltalk for Java Programmers.)


Edit Rename Upload Download Back to Top