Smalltalk doesn’t have a Case Statement

This can bum out a lot of programmers. However, it is possible to simulate a case statement. The Smalltalk-approved way is to use classes and polymorphism, but this can be cumbersome. The case statement is a common enough control flow construct that it should be fairly convenient to use. Building classes to do this is too much work most of the time. (For more information, visit here.)

[Note that in the code examples:

  1. Square brackets delineate block closures.
  2. Code comments are in double-quotes.
  3. The hash (#) signifies a symbolic string.
  4. The caret (^) signifies return from a method.]

You can also use Smalltalk to extend the base class Object to provide a Case Statement. Given Smalltalk’s flexibility, there are many ways to do this, but one that has been suggested to me is the following (thanks to Ricardo Moran):

caseOf: aBlockAssociationCollection otherwise: aBlock
"The elements of aBlockAssociationCollection are associations
between blocks. Answer the evaluated value of the first
association in aBlockAssociationCollection whose evaluated key
equals the receiver. If no match is found, answer the result
of evaluating aBlock."
aBlockAssociationCollection do: [:assoc |
(assoc key value = self) ifTrue: [^assoc value value]].
^aBlock value

Then you can use this Case Statement thusly:

inputValue caseOf: {
#value1 -> [“do something”].
#value2 -> [“do something”].
#value3 -> [“do something”]
} otherwise: [“do something by default”]

Another way to simulate a case statement is by using a dictionary (a collection of key:value pairs). This is appropriate where the cases are simple values, such as strings and numbers. Here’s a general outline:

| dict | "or this could be an instance variable"
dict := Dictionary newFrom: {
#value1 -> ["do something"].
#value2 -> ["do something"].
#default -> ["do something by default"]
"somewhere else in your code..."
(dict at: inputValue ifAbsent: ["default case:"
dict at: #default]) value.

You can leave out the ‘ifAbsent:’ part if you don’t have a default case:

(dict at: inputValue) value.

Of course, you can always use the conditional statement, either in cascading fashion or in serial fashion, to simulate a case statement. This is the most generalized and flexible case statement. For example, in cascading fashion:

condition1 ifTrue: ["do something"]
ifFalse: [
condition2 ifTrue: ["do something"]
ifFalse: [
condition3 ifTrue: ["do something"]
ifFalse: ["do something by default"]]]. "number of closing brackets matches number of ifFalse:"

In serial fashion, you could put the following in a separate method:

condition1 ifTrue: [^"do something"].
condition2 ifTrue: [^"do something"].
condition3 ifTrue: [^"do something"].
"do something by default"

This is cleaner than cascading (and you don’t have to count brackets), but you may need to pass in some variables.

Finally, if your situation involves only a few cases, say, a half dozen, then you can use the brain-dead approach:

condition1 ifTrue: ["do something"].
condition2 ifTrue: ["do something"]. "fall thru..."
(condition2 or: condition3) ifTrue: ["do something"].
condition4 ifTrue: ["do something"]
ifFalse: ["do something by default"].

Here, it doesn’t matter much if you’re testing all the conditions every time; it’s just a few.

[Personal note: It’s just as well that Smalltalk doesn’t have a specific Case Statement. I’ve seen Case Statements in many different languages, and some allow for generalized cases (or expressions), while others are restricted to discrete simple values. Some allow for “fall through.” In general, one size does not fit all. There will be situations where a particular Case Statement is simply not applicable. My prescription lets you apply whichever technique makes most sense. There is a place even for cascading conditionals.

It’s best not to be pedantic. Even in Smalltalk.

(I’ve never used polymorphism to implement a Case Statement. While I’m sure it has its applications, I do not believe it is useful in general. As with ANY control flow construct, a Case Statement should be convenient and easy to use. If it’s more trouble than it’s worth, then people won’t use it. In certain situations, however, the trouble will be worth it.)]

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store