Computer Science Canada [WIP] Smalltalk Whirlwind |
Author: | wtd [ Tue May 15, 2007 10:47 pm ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Post subject: | [WIP] Smalltalk Whirlwind | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
What is Smalltalk? Smalltalk is a purely object-oriented programming language. It makes no compromises for other, earlier programming styles, and wholeheartedly embraces the notion of everything being an object. Why should you care? If you don't, then that's fine. If you want to expand your knowledge, then keep reading. ![]() What do you need? Just download Squeak from http://www.squeak.org. It's available for several platforms, and free of charge. First step Launch Squeak. Feel free to read the material it puts up to start. Then open a new workspace by clicking on the Tools tab at the right and dragging a Workspace out onto the desktop. The Workspace will be the center of our world as we explore the Smalltalk programming language. Very simple expressions All of your favorites are there. We can have integers, floating point numbers and strings. Give it a try. Type something in the Workspace, select it, right-click and select "print it". Alternatively, you can use Alt-p. The expression will be parroted back at you in the Workspace. Slightly less simple expressions Of course, we can have things like mathematical expressions. Keep in mind, though, that Smalltalk is a simple language, and in this case, that means it doesn't respect order of operations in mathematical expressions, so you'll have to use parentheses to be explicit about that. Messages, finally we get to the good stuff In Smalltalk, everything is an object. Those objects are manipulated by sending messages to them, to which they respond. For instance, we could find the absolute value of an integer by sending it a message.
We actually conduct all math by sending messages. Adding two integers, for instance, is just sending the message + to one integer and providing it with an argument. Sending a message to the result of another message is easy.
Another example of a message taking an argument would be finding the maximum of two numbers.
Let's try some output First off, let's open a Transcript window. Go into Tools and drag out a Transcript. Now, back to the Workspace. The Transcript class is an object itself, so we can send it messages. In this case, we'll send it the show and cr messages. In this case cr is short for "carriage return."
Select this code in the Workspace and select "do it" from the menu. You should see a message appear in the Transcript window. You'll note the period. This is used to end a statement. One is not necessary to terminate the final statement. We can simplify this though, since both messages are being sent to the same object.
A quick trip around the block Blocks are important. "Why?" you ask, and are perfectly justified in asking. It's a bold statement with nothing to back it up. Let me take a stab at that now. Smalltalk is strictly evaluated. I can't send a message and expect execution of it to be delayed or even ignored. Not unless I use blocks. A block object can be thought of as essentially the same as an anonymous function in other languages. A very simple block to add one to a number might look like the following.
And of course as this is an object, we can send it messages.
The above has a result of 3. A meaningful example: conditionals A conditional requires that depending on truth, one branch not be executed. Wecan only express this in Smalltalk with blocks.
Here the comparison of 4 to 2 is sent the message ifTrue:ifFalse: to which two blocks are submitted as arguments. The result, since 4 is greater than 2 is 42. Note that there is no special syntax here. There is only message passing. While loops As with conditionals, looping cannot be achieved without blocks. For a while loop, both the test and the body take the form of blocks. For an infinite loop:
Variables While loops aren't much use without variables, so let's introduce them now.
Selecting all of the above, and then selecting "do it" will print a countdown from ten to zero. You'll note that variable names are introduced in a clause before the code that deals with them. At the same time, their types are not declared. Arrays and for loops Array literals are present.
Looping over this is accomplished via messages and blocks.
Many would say that this removes the opportunity to keep track of the index, or requires something ugly.
But this is not necessary.
But surely by looping over the indexes instead of the elements, we can know when we're at the end of the array. This would let us do something after all but the last iteration. It turns out Smalltalk has an answer. Oh, and we'll sort the array for good measure.
Messages can be sent to achieve other common tasks with minimal fuss using blocks. For instance, transforming one array into another.
A quick note: the other way works too If you really must use an incrementing looping idea.
Let's define our own class of object The following shamelessly rips off rdrake's C# whirlwind's Dog example, so we'll start by creating a BasicDog class. First, open the System Browser. Do this by going into the Tools tab and dragging out a Browser. Here you'll see first the categories that classes in Squeak Smalltalk are organized into. We'll want to create our own category called "Dog-Example", so right-click and choose "add item" from the menu. This will prompt you for the same of a new category. Once you've accepted that, you'll see the following in the lower pane of the window.
This is a template for a message we'll send to the Object class which will result in a new class being created.
This is a symbol. But anyway, we need to modify this to create our BasicDog class.
To create the class, simply right-click and choose "accept" or simply Ctrl-s. An entry for it now appears. But really, our BasicDog will have a few instance variables. Modify the code and then save it again.
And we should probably leave a comment. Something along the lines of: Quote: BasicDog is the root class for all of man's best friends.
Save that comment in the customary way. Congratulations, you now have a class! Convenience Just to make things a little nicer, let's add a class message in a new category "object creation."
Now, we can just use the following.
Accessors We still can't actually get any information out of our object. We'll have to change that by introducing a couple of new instance messages under the "accessors" category.
There is no conflict with the names. All messages need an explicit receiver.
Subclassing is fun! So we'll do it again Select the Dog-Example category again and you'll see a new class template again. This time we're subclassing BasicDog, but adding no new instance variables.
Now we just needs to implement some instance messages in an "actions" category.
And finally, a Dog can print information about itself.
One more time! Or, "the beagle did it"
That's all well and good, but... boring So far we've seen text. Now, text rocks my world, but it's not everyone's cup of tea, so how about some graphics? In a Workspace type and execute the following.
You'll now see a blue square on the screen. You can drag it around, and if you right-click you'll see a menu. Select "select" and the Morph you've created will be surrounded with buttons representing actions that can be carried out on the Morph. But let's create our own Morph subclass in category "My-Stuff".
And now we can create a new TestMorph.
Making it do something Now, our Morph does quite a bit, precisely because it is a Morph and has a lot of functionality for free as a result. But, let's make it do something we could not otherwise have had it do. Let's first add a message.
Here we have a temporary variable b which refers to the rectangle formed by the bounds of the Morph. We use that to create a new rectangle which defines the bounds after the Morph has grown in size. But, now we need some way to trigger this growth. Why not use a mouse event? First we have to make the Morph understand that it can handle mouse down events. So we implement the handlesMouseDown message which overrides that in Morph.
Next we'll need to implement the mouseDown message, which overrides the same message in Morph.
With all of this saved, we need only launch a new TestMorph and click on it. Each time you click, it grows by five pixels in each direction. What happened to my right-click?! Used to be we could right-click our Morph, "select" it, and do things to it. Now we just get a change in size. We can still use Ctrl and click to get a menu, but that's not for the lazy. We'll have to make a change.
If the red button (left button) is clicked we send the growInSize message. Otherwise we resend the mouseDown message to super. Dynamic growth What if we want to grow our Morph at an increasing rate? That is, it'll grow by more each time the mouse is clicked. Well, we'll need to have our TestMorph class keep track.
|
Author: | Clayton [ Wed May 16, 2007 5:24 pm ] |
Post subject: | RE:[WIP] Smalltalk Whirlwind |
Excellent stuff as usual wtd! I'm not entirely sure that I understand exactly what Smalltalk is all about, but it definitely sounds like it's worth trying out ![]() |
Author: | Cervantes [ Wed May 16, 2007 6:52 pm ] |
Post subject: | RE:[WIP] Smalltalk Whirlwind |
I didn't know Smalltalk was so syntaxless. Thanks for this, wtd! |