Another Case for Smalltalk
When reading Richard’s post on Smalltalk’s lack of switch/case statement, another implementation occurred to me.
In class Object, define the method switch:
switch
^ Switch new with: self
Then in a new class Switch define methods:
with: val
key := val.
done := falsecase: val do: block
done ifFalse: [
key = val ifTrue: [
result := block value.
done := true]].
^ resultotherwise: block
done ifFalse: [
result := block value.
done := true].
^ result
Then use it like:
42 = (3 switch
case: 1 do: [ 3+10];
case: 3 do: 42;
otherwise: 17)
which should look pretty natural to programmers coming from virtually any language. It could also be extended to have a caseOneOf:do: to accept a collection of values, and the otherwise: block could take an optional parameter with the original value. For completeness, here they are:
caseOneOf: aCollection do: aBlock
done ifFalse: [
aCollection do: [:each |
key = each ifTrue: [
result := aBlock value.
done := true.
^ result]]].
^ resultotherwise: aBlock
done ifFalse: [
(aBlock isBlock and: [ aBlock argumentCount = 1 ]) ifTrue: [
result := aBlock value: key
] ifFalse: [
result := aBlock value
].
done := true].
^ result
With the addition of a class method for Switch:
if: aBoolean do: aBlock
^ (self new with: Object new) if: aBoolean do: aBlock
and an associated instance method:
if: aBoolean do: aBlock
done ifFalse: [
aBoolean ifTrue: [
result := aBlock value.
done := true]].
^ result
you would get a cond-like statement form:
Switch
if: x squared >25 do: [ "something" ];
if: x negated < 10 do: [ "something else" ];
otherwise: [ "yet something else" ]
This is actually a much more general statement than switch or cond in other languages, since you can freely intermingle if:do: and case:do: methods, like:
(x+3) switch
case: 1 do: [ 3+10];
if: x squared >25 do: [ "something" ];
case: 3 do: 42;
if: x negated < 10 do: [ "something else" ];
otherwise: [ : key | key-5]