| Edit | Rename | Upload | Download | Back to Top |
It's instructive to see how easy it is to write. (I shall present Paul Baumann's case-statement construct as it is, I think, hard to find on the web. Other case-statement utilities for Smalltalk have been written by Peter van Rooijen and by a Squeaker.) We know that curly-bracket-language:
if (aBoolean)
then {some_code}
else {other_code}
becomes
aBoolean
ifTrue: [someCode]
ifFalse: [otherCode]
in Smalltalk. It's fairly obvious, therefore, that curly-bracket language:
switch (aValue)
case {match_code1} : {action_code1; break;}
case {match_code2} : {action_code2; break;}
...
default {other_code;}
needs to become something like
aValue switch
case: [matchCode1] then: [actionCode1]
case: [matchCode2] then: [actionCode2]
...
default: [otherCode].
in Smalltalk. This won't quite work as its stands since, unlike the Java-like version, ours has to be built out of existing program elements, not reserved words, so needs to separate the arbitrarily repeated case:then: elements in some standard way. Full-stops are no use:
aValue switch case: [matchCode1] then: [actionCode1].
aValue switch case: [matchCode2] then: [actionCode2].
...
aValue switch default: [otherCode].
has no benefit over if-statement lists. Nested brackets are no use:
((((...((((aValue switch
case: [matchCode1] then: [actionCode1])
case: [matchCode2] then: [actionCode2])
...
default: [otherCode]
would send each case:then: to the result of the previous one but it's already obvious that we can write a case-statement as nested ifTrue:IfFalse: statements
matchValueCode1 ifTrue: [actionCode1] ifFalse: [
matchValueCode2 ifTrue: [actionCode2] ifFalse: [
...
ifFalse: [otherCode]]]]...]]]]].
and the above gives us just as many brackets to nest. What we need is to send each case:then: in turn to the result of the switch method in a way that needs no brackets. In Smalltalk, that is done by a cascade:
aValue switch
case: [matchCode1] then: [actionCode1];
case: [matchCode2] then: [actionCode2];
...
default: [otherCode].
Now we have worked out the case:then: protocol, we can write a simple test. The test falls over because the switch method does not yet exist. It must be understood by any value, i.e. by any object, and must return something that responds to repeated case:then: messages; sounds like switch had better return an instance of a new class, which we may as well call Case.
Object
subclass: #Case
instVars: 'criterion satisfied response'
Case>>for: anObject
^self new criterion: anObject
Object>>switch
^Case for: self
This makes switch return an instance of class Case that knows:
Case>>case: oneArgTestBlock then: execBlock
"The oneArgTestBlock must return a Boolean value when passed the criterion of the receiver."
satisfied ifFalse:
[(oneArgTestBlock value: criterion) ifTrue:
[response := execBlock value.
satisfied := true]].
Case>>default: execBlock
satisfied ifFalse: [response := execBlock value].
^response
This works and offers possibilities for further development.
Case>>caseIs: testObject then: execBlock case: [:caseCriterion | testObject = caseCriterion] then: execBlock. Case>>caseIsAny: testCollection then: execBlock case: [:caseCriterion | testCollection includes: caseCriterion] then: execBlock.
Case>>isSatisfied
^satisfied == true
accessor in the case:then: and case:process: methods, and checking satisfied isNil ifTrue: instead of satisfied ifFalse: in the default method.
And there you have it; a case-statement that allows arbitrary matching code and is easy to extend. It runs in any dialect of Smalltalk. See Paul Baumann's article in The Smalltalk Report (August 1997, Vol 6 No 9) for a fuller description.
However I recommend using the other approaches:
I would contend that in normal OOP there is no real need for a switch statement. Sometimes, when interfacing to a non-OOP world (like receiving and dispatching WM_XXXX Windows messages that are not objects but just integers), then a switch statement would be useful. In these situations there are alternatives (like dispatching from a Dictionary) and the number of times they crop up doesn't warrant the inclusion of additional syntax.
(The same goes for breaking out of a loop without returning. You just don't need it that much; in my 8 years of programming Smalltalk I can recall having wanted a non-returning break statement construct about twice!) -- Andy Bower
(Back to new code syntax.)
(Written by Niall Ross as part of Smalltalk for Java Programmers.)
| Edit | Rename | Upload | Download | Back to Top |