LINUX GAZETTE

[ Prev ][ Table of Contents ][ Front Page ][ Talkback ][ FAQ ][ Next ]

"Linux Gazette...making Linux just a little more fun!"


Bags o' Fun

By Jason Steffler

Abstract

    For those who haven't read the previous articles, be sure to read the statement of purpose first.  This month, we're going to discuss inheritence, polymorphism, and abstract classes as well as introducing some collection objects.  For those looking to read the whole series locally or information about upcoming articles, you can check the MST page.  For those looking for further information on learning Squeak, here are some good resources.

Quote of the day

"Why Smalltalk? Smalltalk uses a simplified version of English. Nouns and verbs. Object are the nouns. Verbs are messages sent from one object to the next. Easy as 1, 2, 3. It is no longer necessary to write cryptic programs.  This means that almost anyone can learn to write Smalltalk programs."
        - Peter William Lount

Inheritence

    Last month, we were using aPerson object for illustrative purposes.  This month we'll only build on this example briefly, as it quickly gets too contrived for my liking.  Also, this is a good opportunity to introduce the collection objects of Smalltalk.  We'll return to aPerson next month though, as the emphasis will be on the building aspect, and not on the object itself.
    The notion of inheritence in OO is very similar to the normal use of this term.  Just like a person can inherit certain characteristics from their parents, so too can objects inherit certain characteristics from their parents.  Objects inherit the methods and instance variables of their parents, among other things.
    To get this discussion going, lets introduce the object anOrderedCollection, whose class is OrderedCollection.  This is a very common object to use in Smalltalk.  An OrderedCollection is just what it sounds like:  it's a collection of objects where order is important.  To better position the topics at hand, it'd useful to have an idea of how you can use this type of collection:

[ex1]
    "Inspect this code.  Here we're creating a new OrderedCollection, and asking it to add 1, then add 2, then add 3, then finally return yourself"
    (OrderedCollection new)  add: 1; add: 2; add: 3; yourself.

[ex2]
    "This is normally not written on one line, but is written like this:"
    (OrderedCollection new)
        add: 1;
        add: 2;
        add: 3;
        yourself.

    Here, we're asking the class (remember, this is a blueprint for creating objects) OrderedCollection to create a new collection.  Then we're asking the new collection to add 1 to itself.  Then we're asking the same new collection to add 2 to itself, then 3, and then finally we're asking the collection to return itself.  You normally don't have to send that last message to an object, as the default return is the object itself (we call this the receiver of the the messages), but the message add: returns the parameter you're passing, so in this case, if we want to see the OrderedCollection that we're creating, we need to ask it to return itself as the last message send.  This may be a little confusing; I showed the above snippet as it explicitly creates a new object.  You could get the same results by inspecting the below two snippets, that don't explictly create a new object - this is done implicitly from the message sent:

[ex3]
    "Here, we're asking the OrderedCollection class to give us a new OrderedCollection object with the values 1, 2, and 3 in it."
   OrderedCollection with: 1 with: 2 with: 3

[ex4]
    "Here, we're asking the OrderedCollection class to give us a new OrderedCollection object with all of the values 1, 2 and 31"
    OrderedCollection withAll: #(1 2 3)

[ex5]
    Now, if you print it to the above code, you'll see an ASCII representation of the object:  OrderedCollection (1 2 3 ).  When you inspect the above code, and click on self you will see:

[ex6]
    There are several ways that we could make an ordered collection with a fourth Integer in it, here's a neat way.  Say that you have this OrderedCollection with only the first 3 integers in it, and realize 'wups, I actually wanted 4 integers in it.'  You don't have to go back to the code you typed in above and redo it, you can just ask the object you're inspecting to add a fourth integer to itself:

[ex7]
    Highlight the code entered in the bottom pane, and do it.  Here, you're asking the object itself (self) to add 4 to itself.  If you have self highlighted, you'll notice that it is updated (if you don't have self highlighted, then click on it to see the updates.  You'll see:

    This is an illustration of being able to view and manipulate objects in real time, which is Immensely Powerful.  If you're coding along and something isn't quite working right, you can stop execution, grab the troublesome object and see exactly what is going on.  If you want to simulate certain conditions, you can just change the object directly.  For example, say you realized that you shouldn't have the integer 4, but rather the string 'four', you can click on the fourth element, delete 4, and tye in 'four', then middle click>accept. The fourth element in this collection is now the string 'four'. Try clicking on the 3rd element, then back to the fourth element to confirm this, you'll see:

    ...and remember, we did all this without the hassle of compiling, linking, and running the compiled program!  Ok, now that we have an idea about how to create a collection, we're going to do something with this collection, lets add up the integers in the collection.  To do this, you can do it the following snippet:

[ex8]
    | anOrderedCollection aSum |
    aSum := 0.
    anOrderedCollection := OrderedCollection withAll: #(1 2 3).
    anOrderedCollection do: [:anElement | aSum := aSum + anElement].
    aSum inspect.

    Here, the lines of code mean:
    1) declare temporary variables
    2) initialize the sum
    3) create a new ordered collection, assign it to one of the temporary variables
    4) ask the ordered collection to do something for each element.  For each element, we're asking the sum to add the element to itself.
    5) here, we're asking the sum to open an inspector on itself (yeah, you can do this programatically - cool eh?)

    For the folks with programming experience, you'll note that we didn't have to worry about bounds checking, or the size of the collection, or declaring temporary variables to index the collection - this is all handled by the collection.  Very nice and it helps to reduce errors.  We very naturally just asked the ordered collection to do something with each element.
    Back to inheritence now, as the name suggests, OrderedCollection is a type of Collection, and inherits methods and instance variables from Collection.  To be more precise, it inherits from a class called SequenceableCollection, which in turn inherits from Collection.  Now, I could use UML, or any number of other industry software modeling diagrams here, but I want to save time so I'm going to use a textual shorthand for outlining class relationships - I'll denote inheritence by tabbing, so indicating the above inheritence looks like this:
    Collection
        SequenceableCollection
            OrderedCollection

    You can think of this as OrderedCollection is a type of SequenceableCollection, which is a type of Collection.  For example, a creation method we used - withAll: is inherited from Collection, I'll show this class method by:
    Collection
        >>withAll:
        SequenceableCollection
            OrderedCollection

    Both Collection, and SequenceableCollection, are what we call abstract classes - classes that would never instantiate an object themselves, but serve as good logical building points.  Here, it doesn't matter if we have an OrderedCollection, or a SortedCollection, or a Bag (an unordered collection), or whatever - we'd want all of them to know how to respond to withAll:. Here's the sweet thing:  we implement the method that all these classes should respond to in one spot, and reuse it. So, if you need to change withAll: for these classes, then there's only one spot to go to.
    If you need to have an exception to the rule, say you have have a Heap2 class that needs to implement the withAll: method differently, then you can do what is called overriding the method in Heap.  Adding Heap to our outline, and indicating abstract classes in italics gives us:
    Collection
        >>withAll:
        SequenceableCollection
            OrderedCollection
            Heap
                >>withAll:

    Note:  when we send the withAll: message to Heap or to OrderedCollection, these two classes have different implementation of the same message - this is known as polymorphism. This is another one of those esoteric terms that really means something pretty simple.
    The corollary of polymorphism is a very powerful one though, it allows you to get out of a decision making frame of mind, and get into a commanding frame of mind. This allows us to get away from a common procedural programming trait - having lot of code that is checking stuff and conditionally doing stuff (if it's an OrderedCollection, do this, if it's a Heap, do this, if it's a Bag, do this, etc), and lets us just do stuff.  It doesn't matter what type of collection it is, when we ask it to do withAll:, it will do the right thing!
    Finally, if we also add the above mentioned SortedCollection and Bag (<groan> here's where this month's title pun comes from ;-), we get:
    Collection
        >>withAll:
        Bag
        SequenceableCollection
            OrderedCollection
                SortedCollection
            Heap
                >>withAll:

    It's easy to see how there are lots of opportunities for reuse here, it's generally a good thing when you can code something in one spot, and have many objects reuse that one implementation.  That way, when you have to make an udpate, you only update that one spot and don't have to worry with tracking down many different spots and keeping the update in synch.
    Now we're going to start getting to the question of how we know what objects are where and how to use them.  As with other topics in this series, I'm introducing this one a bit at a time as well.  A common problem for Smalltalk beginners is that they're overwhelmed with the rich class library as there are thousands of objects you can use.  To help reduce this problem, I've extended one of the Smalltalk browsers and made a ScopedBrowser.  This is a good example of the reflectiveness we mentioned earlier - I was able to extend or alter the behavior of the IDE to suit my needs.  This ScopedBrowser will only show you the classes we need to concentrate on for this article.  My intent is to add to the scope that is being browsed over time as more objects are introduced.  For this time, I've included all the above mentioned collections objects as well as a couple more collections objects for those interested (a total of 9 classes).  To open this browser, you first need to file in the MakingSmalltalk-Article3.st code to your image (see article 2 on how to do this).  Then open the browser by doing the snippet:

[ex9]    [Squeak-only-suspected]
    ScopedBrowser openBrowserForArticle3

    For the read-along folks, this is what you'll see after navigating to the withAll: method:

    (Note: I set my browser colour to purple - the default colour is green, I'll come back to customization in a future article)
    To find the withAll: method, click on the class button, then Collections-Abstract>Collection>instanceCreation>withAll:
    This browser has 5 panes and 3 buttons, from left to right and top to bottom:
        pane 1: shows categories - these are collections of classes (pun intended)
        pane 2: shows classes
        pane 3: shows categories - these are collections of methods
        pane 4: shows methods
        pane 5: shows Smalltalk code
        button 1: toggles the browser to show the instance methods of the object
        button 2: toggles the browser to show the class comments
        button 3: toggles the browser to show the class methods of the object
    Now, if we step back a little bit, and click on Collections-Sequenceable>OrderedCollection, you'll see:

    Note that the code pane shows who OrderedCollection inherits from, as well as their instance variables, if you then go back to the abstract classes and click on SequenceableCollection, you'll notice that it inherits from Collection just as we discussed.  Take some time poking around these classes and get comfortable with navigating in this browser.  Look for the classes and methods we discussed above.
    Finally, I'm going to introduce one more browser - the hierarchy browser.  This one is good when you're concentrating on hierarchies and inheritence when you're coding.  To open it, first click on OrderedCollection again, then middle-click>spawn hierarchy.  You'll see:
[ex10]

    Note, that this browser hasn't been scoped, and shows the full hierarchy.  Notice that Collection inherits from an object called Object - no surprise here, most things about Smalltalk are just what you would expect.  Finally, the topmost object is ProtoObject, which implements some really fundamental methods.  The question naturally arises:  "What does ProtoObject inherit from?".  The answer is nothing, or nil to be more precise.

Looking forward

    The next article will cover the making of aPerson; we'll go over not only the basics of creating objects, but we'll also discuss what the Smalltalk code that we're writing means.

A Sweet Squeak

This section won't explore/explain code or example, but merely present a neat thing to try out.  This time, we're going to look at downloading projects.  Remember in article 1 when we created a new project?  Well, you can not only save the project to transfer across images, but you can drop it on the internet and download it directly to your image too.  Here's an example, do this:

[ex11]    [Squeak-only-suspected]
    Project thumbnailFromUrl:     'http://www.squeak.org/Squeak2.0/2.7segments/SqueakEasy.extSeg'

    For the read-along folks, you'll see a simple turtle game project, and when you enter the project you can direct the turtle by entering Smalltalk code:

Questions and Answers

These are the answers for questions on previous articles that I could work through in my limited time available.  I picked out the ones I thought most appropriate for the series.  If you want a faster response, or I didn't get to your question, try posting your question to the comp.lang.smalltalk newsgroup, or the Swiki.

Q: How compatible with [VisualWorks, VisualAge, Smalltalk/X, Dolphin, etc] Smalltalk will the code examples be?
A:  Though I'm not writing these articles with code portability in mind, and I'm not doing any portability testing, much of the basic code should be compatible.  By basic code, I mean things like how collections are used, how classes are declared, instance variable use, etc.  Traditionally where the different flavours of Smalltalk differ most is in GUI code.  With Squeak specifically, some of the cool stuff we're going to look at isn't portable to other flavours, for example:  the halo stuff, morphic stuff, and downloading projects.
    What I'll start doing though, is any code that I a priori suspect is Squeak specific, I'll tag with [Squeak-only-suspected].  NOTE:  this will only indicate my suspicion - I don't plan on spending time on testing it in different flavours, or searching for ways to accomplish the same task in a different manner.
    This would be a great use of the Linux Gazette's talkback sections - if other Smalltalkers note what does and doesn't work in other flavours, they can post this info.  Also starting with this article, I'll start indexing the examples so they're easier to refer to for this purpose (ie: ex1, ex2).  I haven't done this yet, as I wanted to keep the series informal, but I expect enumerating examples will make it easier/clearer to post talkbacks.  If you don't like the enumerating - post a talkback.

Article Glossary

This is a glossary of terms that I've used for the first time in this series, or a term that I want to refine. 
abstract class
        A class that would never instantiate an object itself, but serves as good logical building point for other classes that do instantiate themselves (concrete classes).  Abstract classes are indicated in italics in class outlines.
class method
        (def1 - simple) A method that a class implements (as opposed to an instance), usually to create a new object.  I denote a class method by: >>aClassMethod
concrete class
        A class that would instantiate an object itself.
instance method
        (def1 - simple) A method that an instance of an object implements (as opposed to it's class).  I denote an instance method by: >anInstancemethod
polymorphism
        When two different objects interpret the same message differently by implementing two different methods.
receiver
        The receiver of a message send.  The object that receives a message send.  For example, if we say aPerson sing, the receiver of the sing message is aPerson
[Squeak-only-suspected]
       This tag is for any code that I a priori suspect is Squeak specific.  NOTE:  this will only indicate my suspicion - I don't plan on spending time on testing it in different flavours, or searching for ways to accomplish the same task in a different manner.

Footnotes

[1] For those folks who have programming experience, the parameter that we're passing here is an Array, you can just highlight the array and inspect it too if you like.  The reason I'm not using an Array for illustrative purposes here, as because they are not as flexible or user friendly as an OrderedCollection.  Where arrays have a fixed size, an ordered collection grows or shrinks as you need it to.
[2] For those folks never lucky enough to be in a comp sci class that studies heaps and stacks and other data structures  adnauseam, a heap is a type of binary tree in which the value of each node is greater than the values of its leaves.

Statement of purpose

    When I wrote the first Making Smalltalk with the Penguin article back in March of 2000, my target audience was experienced programmers who didn't have much exposure to OO programming or to Smalltalk.  The article's intent was to give an overview of my favourite programming language on my favourite operating system.  Since then, I've had a fair amount of email asking introductory type questions about Smalltalk and OO programming.  So I thought I'd try my hand at a small series.
    The target audience for this series are people new to OO or new to programming altogether.  The intent is to not only introduce OO programming, but to also spread the fun of Smalltalking.  Why do this format/effort when there's lots of good reference material out there?  Two reasons really:  1) Tutorials are great, but can be static and dated pretty quickly.  2) An ongoing series tends to be more engaging and digestible.
    To help address the second reason above, my intent is to keep the articles concise so they can be digested in under an hour.  Hopefully, as newbies follow along, they can refer back to the original article and make more sense of it.  I plan on having a touch of advanced stuff once in a while to add flavour and as before, the articles are going to be written for read-along or code-along people.

Why Smalltalk?

    I believe Smalltalk is the best environment to learn OO programming in because: In particular, I'm going to use Squeak as the playing vehicle.  You'll notice this is a different flavour of Smalltalk than I used in my first article.  I've never used Squeak before, so this'll be a learning experience for me too.  The reasons for this are:

Smalltalk Code

No listings this month


Copyright © 2000, Jason Steffler.
Copying license http://www.linuxgazette.net/copying.html
Published in Issue 61 of Linux Gazette, January 2001

[ Prev ][ Table of Contents ][ Front Page ][ Talkback ][ FAQ ][ Next ]