ST 4U 200: A Case Statement in Smalltalk
Today's Smalltalk 4 You looks at implementing a case statement construct in VA Smalltalk. If you would like to download the code, links are below, in the walkthrough section. If you have trouble viewing it here in the browser, you can also navigate directly to YouTube. To watch now, click on the image below:
If you have trouble viewing that directly, you can click here to download the video directly. If you need the video in a Windows Media format, then download that here.
You can also watch it on YouTube:
Today we'll build a simple case statement class in VA Smalltalk. Why? People are often surprised that Smalltalk does not have one, so building one is a good way of showing how Smalltalk works to a new user, while implementing a concept that's familiar to them. To get started, define a new class:
Object subclass: #CaseStatement instanceVariableNames: 'cases defaultCase ' classVariableNames: '' poolDictionaries: ''
The cases will be stored in a dictionary, and the default case will be held in the defaultCase variable. In this example, we'll default that to a simple Transcript write. Next, let's add the instance creation code:
addAll: associationsOrDictionary ^self addAll: associationsOrDictionary default: self simpleDefaultCase. addAll: associationsOrDictionary default: default ^self new addAll: associationsOrDictionary default: default
Here we allow for the definition of a default case, and for the inbound cases to be either a dictionary or a collection of associations. We'll see how that gets handled in the instance code:
addAll: associationsOrDictionary default: default |associations | associations := associationsOrDictionary isDictionary ifTrue: [associationsOrDictionary associations] ifFalse: [associationsOrDictionary]. associations do: [:each | self addCase: each]. defaultCase := default
Note the conversion of string keys to symbols - that ensures that we have unique keys. For the values, we simply assume any object that responds to #value. It'll probably be a block, but that's not all that could be done there. Now let's look at the execution:
caseAt: keyName "execute the corresponding value" | key val | key := keyName isString ifTrue: [keyName asSymbol] ifFalse: [keyName]. val := self cases at: key ifAbsent: self defaultCase. ^val value
Again, we convert the key if necessary, then do a lookup. If that fails, we simply use the default case. Finally, we send #value to the looked up case. That's it - we now have a case statement in Smalltalk.
Want the code? Download it here.
Need more help? There's a screencast for other topics like this which you may want to watch. Questions? Try the "Chat with James" Google gadget over in the sidebar.
Technorati Tags: smalltalk, va smalltalk, case statement
Enclosures:
[st4u200-iPhone.m4v ( Size: 5173702 )]
Comments
Re: ST 4U 200: A Case Statement in Smalltalk
[anonymous] February 29, 2012 11:13:56.820
In the special situation where a variable will hold a symbol, and the symbol values are from a small set of predefined values, I recently did something that I like even better than a pseudo-case statement.
Using doesNotUnderstand: protocol, I rolled the ability do something like:
mySymbol:=#left.
someValue:=mySymbol left:[...] right:[... ] up:[.. ] down:[...] ifNone:[...]. (the blocks could also be just values)
Then the doesNotUnderstand: in ByteSymbol simply picks apart the selector, looking for a match with the symbol value in any portion of the selector.
Syntactically very small, and also very readable. Only drawback is the overhead of doesNotUnderstand: processing.
Re: ST 4U 200: A Case Statement in Smalltalk
[anonymous] February 29, 2012 16:41:46.210
The usage of a case statement like that is not very readable.
I once programmed a class called SwitchStatement with the following usage:
variable := 4.
result := variable switch
case: 3 then: 'three';
case: [ 16 / 4 ] then: [ 'four' ];
case: [ :var | var == 5 ] then: [ :var | var * 2 ];
default: [ 42 ].
This produces much more readable code.
3 types of arguments are legal. The default statement is optional but the statement will throw an error if no case matches when no default is specified.
Object class was extended with the method
Object>>switch
^ SwitchStatement for: self