Lab4


Lab 4: Blocks, Collections, and Perform

This lab works with some of the most powerful programming features Smalltalk offers: blocks, collections, and the perform: method.

Block Basics

A block in Smalltalk is a sequence of statements enclosed in square brackets. It can be storred in a variable or passed to other statements as an argument, much like an integer or a string. The statements in a block can be evaluated by sending it value, value:, value:value:, or value:value:value:, and specifying the actual parameters for the block to use. For more details, refer to page 516-517 of Coad/Nicola book.

To get started, open up a workspace and try doing a "print it" on each of the following expressions. Try to gues what each will do before you print the result, and see if it did what you expect. Understanding these simpler scenarios will help when you do more complex ones below.

[ 3 + 4 ]
[ 3 + 4 ] value
[ :x | x + 5 ] value: 1
[ :x :y | x + y ] value: 3 value: 4
b := [ :x | x - 1 ]
b value: 5
b value: 20
bb := [ [ 2 + 3 ] ]
bbValue := bb value
bbValueValue := bbValue value

The Collection Class and Friends...

Simply put a Collection represents a group of objects. The objects that a Collection is comprised of are called elements. The arrays you probably met in CS 1502 are one example of Collections, but Smalltalk has several more.

Here is an overview of some of the collection classes available in Smalltalk:

What Can You Do With a Collection?

A lot! Browse through the abstract Collection and SequenceableCollection classes some time! Because the listing is so long, here are some of the most commonly used methods, for your reference. Don't bother memorizing them, because you can always look t hem up in System Browser.
       adding
                   add: newObject
                             Include the argument, newObject , as one of the receiver's
                             elements. Answer newObject.
                   addAll: aCollection
                             Include all the elements of the argument, aCollection,
                             as the receiver's elements. Answer aCollection.
       removing
                   remove: oldObject
                             Remove the argument, oldObject, from the receiver's
                             elements. Answer oldObject unless now element is equal
                             to oldObject, in which case report that an error occurred.
                   removeAll: aCollection
                             opposite of addAll.
       testing
                   includes: anObject
                             Answer whether the argument, anObject, is equal to one
                             of the receivers elements.
                   isEmpty
                             Answer whether the receiver contains any elements.
                   occurencesOf: anObject
                             Answer how many of the receiver's elements are equal to
                             the argument. anObject.
       enumerating
                   do: aBlock
                             Evaluate the argument, aBlock, for each of the receiver's
                             elements.
                   select: aBlock
                             Evaluate the arguments, aBlock, for each of the receiver's
                             elements. Collect into a new collection like that of the
                             receiver, only those elements for which aBlock evaluates
                             to true. Answer the new collection.
                   collect: aBlock
                             Evaluate the argument, aBlock, for each the receiver's
                             elements. Answer a new collection like that of the
                             receiver containing the values returned by the block on
                             each evaluation.
	accessing
		   at: anIndex
			     Obtain a value from a Collection.  For Arrays,
                             anIndex is an Integer.  For Dictionaries, it
                             can be anything.  
		   at: anIndex  put: anObject
			     Replace an element in a collection with something else.

queries size how many elements are in the collection?

Some Basic Collections

Okay, now you try it. Type the following into a workspace and do it:
                             MySet:= Set new.
                             MySet add: 'a'.
                             MySet add: 2390.
                             MySet add: ( Set new )

Highlight the whole thing and then choose do it. Declare MySet as a global when asked. Then highlight MySet and choose inspect. Peruse around inside of the set for a while. Then select the MySet add: 2390 line and print it. What should have happened? Check the tally to see if you where right.

Now let's try out a Bag. Enter the following:

                             MyBag := Bag new.
                             MyBag add: 'a'.
                             MyBag add: 2390.
                             MyBag add: ( Set new )

Do the same sequence of operations as you did for Set. Should you get the same results?

Now, let's try out an Ordered Collection. [ For the purposes of the this example let's make all the elements the instances of the same class. They don't have to be.]

                             MyOrdered := OrderedCollection new.
                             MyOrdered add: 'Swimming'.
                             MyOrdered add: 'Baseball'.
                             MyOrdered add: 'Track&Field'.
                             MyOrdered add: 'Gymnastics'

Again, do it, inspect MyOrdered and observe. Next try the following. In what order will the elements be in?

                             MySorted := SortedCollection new.
                             MySorted add: 'Swimming'.
                             MySorted add: 'Baseball'.
                             MySorted add: 'Track&Field'.
                             MySorted add: 'Gymnastics'

Conversions

There are several methods available for converting a collection from one type to another. Try printing each of these two expressions:

                             MyBag asOrderedCollection
			     MyBag asSet

Dictionaries

Sometimes it is useful, convenient, and/or efficient to look data up by a key.

                             MyTable := Dictionary new.
                             MyTable at: 12345 put: MySorted.
                             MyTable at: 12 put: MyOrdered ; at: 505 put: MyBag

You should now the routine by now... Close the inspector window and then invoke do it on the following.

                             MyTable at: MyOrdered put: MySorted

Objects can serve as keys. After all numbers are objects too. Reinspect MyTable. You can add to dictionaries this way too.

                             MyTable add: (Association key: #aKey value: #aValue )

Enumeration: Blocks and Collections Together

Collections aren't very useful until you do something with their contents. In Java you might have created a for loop and iterated through an array. In Smalltalk, methods that iterates over a Collection are provided for you, so that you don't have to explicitly do things like create a loop variable.

The most commonly used enumeration method is do:. do: takes one argument, a block, and evaluates that block with each of the elements in the collection in turn. For example, try each of the following, and observe the Transcript:

                   MySet do: [:anObj | Transcript show: (anObj printString ).
                                       Transcript cr ].

MyBag do: [ :anObj | Transcript show: ( anObj printString ); cr ]

do: is sufficient for most enumeration tasks in Smalltalk. However, there are other methods available that can be a little more convenient. For example, try printing the results of these two statements:

                   MySorted select: [ :anObj| anObj = 'Baseball' ]
                   MyOrdered collect: [ :anObj | anObj = 'Baseball' ]
		   MySorted collect: [ :anObj | anObj, ' is a happy String' ]

For the first, if the block evaluates to true then that element is put a new collection of the same type. For the second, the result of the block is used as the new element in the collection of the same type being created.

Perform

One last topic! Smalltalk let's you call a function just using its name. For example, instead of the simple code "7 squared", Smalltalk allows you to type:
		messageName := #squared.
		7 perform: messageName.
Try printing the above--does it give you the same as "7 squared"?

There is also a perform:with: method which allows you to give arguments:

		7 perform: #min:  with: 12

7 perform: #+ with: 12

So What do you Actually Do?

To show you know how all this works, write blocks to do the following: Your code should work something like this:
    sum2 := [ "your job..." ].
    avg2 := [ "your job..." ].
    avg := [ "brilliant averaging code goes here" ].
    fred := [ "brilliant code for doing a Fred I/O goes here" ].
    doit := [ "your job" ].
    blocker := [ "your job" ] 


sum2 value: 1 value: 3 "should return 4" avg2 value: 1 value: 3 "should return 2" avg value: #(1 2 4 5 3) "should return 3" fred value: #(1 1 4) "should print 'odd', 'odd', and 'even', to Transcript" doit value: 1 value: 3 value: #+ "should return 4" doit value: 1 value: 3 value: #max: "should return 3"
b := blocker value: #+. b value: 1 value: 3. "should return 4" b := blocker value: #min:. b value: 1 value: 3 "should return 1"

Turn In

Send a mail message as follows:

Cut and paste does work between Squeak and other windows programs; cut and copy are on the middle-mouse-button menu in Squeak workspaces.


News Page | CS2390 Sp'98 Home Page | CS2390 CoWeb | STABLE | BOOST
Questions/comments/concerns to guzdial@cc.gatech.edu
Page last updated 4/29/98; 10:26:03 AM