The general idea behind exception handling is that you assume everything works, and so you don't check return values.
(some condition) ifFalse: [^self]
(some condition) ifTrue:
I don't think I understand this properly yet. There is something odd about asking, for example a list to do something, and for the return result to be the list. I am not sure how my coding would cope with that, i.e. rather than getting a failure message or something like that. More pondering required.
In the meantime, this section from Smalltalk By Example, seems really helpful. I am going to make sure any of my methods follow these rules - if only to avoid confusing myself further.
Often the method name will tell you what type of object will be returned. For example, method names that start with is will usually return a Boolean, true or false. For example,isEmpty,isNil. Messages that start with as will usually return the thing specified. For example,asSortedCollection sent to a collection will return aSortedCollection. The asNumber message sent to a string will return a number of the appropriate type. (However,asString is not implemented by numbers so you should use printString or displayString instead.)
Methods that add objects to collections, such as add: and at:put:, return the object that is added. Methods that remove single objects from collections, such as remove: and removeFirst, return the object that was removed. Because of this it's worth knowing about the yourself message. The following example illustrates how the use of yourself ensures that collection contains the list rather than the last object addedcollection := List new
Consistency and predictability are great virtues, so when adding these types of methods to your own classes, follow the common usage patterns. Otherwise you'll confuse every programmer who looks at or uses your code.
We will now evaluate the desirability of the selected nouns as classes:
- Address. If the address included the name of the city, postal code, province or state, and other information, we would implement it as a class. As it is, an address is just a string of alphabetic and numeric characters and strings are already in the library. We thus remove Address from our list of candidates.
- Apartment. Yes, we will implement this concept as a new class because it represents an object that holds a lot of apartment information together and no related class exists in the library. The class will be called Apartment and we will decide shortly what exact meaning it will have.
- Building. Another and non-trivial object that does not have a counterpart in the library and will have to be implemented. The class will be called Building.
File. The concept of a file is implemented in VisualWorks library and does not require a new class.
The reason I found this so helpful is that it provides some really useful heuristics for object modelling. If what you are trying to store exists as a simple object, e.g. a string for address, then don't bother creating a new class. If, on the other hand, it is a more complex 'type', AND, you can't find an existing object that will do. Create a new one.
Blindingly obvious and really helpful
I downloaded Ivan Tomek's Joy of Smalltalk, which is a very good book - not squeak oriented, but very interesting none the less.
I was in the midst of reading his approach to development when I came across this phrase
In the first iteration, we will focus on the ‘normal’ sequences of events and leave the
abnormal alternatives (such as what happens when the information file does not exist) for the next iteration.
Doh! that should have been on my list of what I did wrong. I definitely over-engineered the initial attempt, and that contributed to my confusion.
It didn't go well!
Actually, I found the whole process both fascinating and frustrating. I started by sketching out - on paper - a class hierarchy, and identifying the properties of each class. Having done that, I then started implementing them in Squeak. As a side note, I am actually beginning to like the Squeak UI! I suspect this is a little like discovering that the mauve kitchen in your new flat is actually quite pleasant, after you get used to it. Actually, that probably isn't fair. I think what is really happening is that I am starting to understand Squeak's tools, and appreciate their usefulness. And, as a result, the very dodgy appearance is fading into the back of my consciousness.
OK, back to the code. I implemented the root class easily enough, and started building the others. However, very soon, I found that I was running around changing the object types used by the various instance variables. This is turn led me to change the method selectors, and that broke the message sends.
What was so fascinating about all this was that I was managing to confuse myself when I only had 4 classes!
Having had a chance to think about this - and ask for advice on the list - I have realised some of my mistakes:
- I identified object properties whereas I should have thought about methods - in other words what did I need the objects to do.
- I didn't create use cases. I know it seems crazy to do that for such a simple system, but as my experience shows, it is very easy to get it wrong.
- I should have written the tests first - yes, I know, that's what the book says, I just wanted to get on with building things :-)
So, let's have another go.
The great part is that tiny code can produce amazing results.
Emboldened by this discovery, I decided to start thinking about the design of my first 'real' application. It is still really just an experiment, but it is something I want to make work, because I need to compare the development process/effort with that of doing it all in Flex.
So, I have spent the afternoon drawing objects and wondering about what should go where. Although all programming involves this type of thinking, the Smalltalk hierarchy really makes one think in a different way. For example, I have just spent the last 10 minutes comparing Dictionary and SortedCollection; trying to establish which object would be the better container for a list of clients (in the end I have gone with Dictionary because it seems to offer much better access).
The whole experience is a lot like standing in a hardware store looking at various nuts and bolts, trying to work out which to use.
To do this, you have to override Class>>initialRequest. Something like this:
super initialRequest: aRequest.
aRequest fields at: 'action' ifPresent:
[:action | 'put'=action ifTrue:[self confirm: 'you want to put']. 'get'=action ifTrue:[self confirm: 'you want to get?']].
I have a little way to go on this, because at the moment it is only processing the url argument, whereas I want to get to the contents of a 'posted' document. However, I am sure that will just be an object message away ;-)
count = 0
ifTrue: [(self confirm: 'are you sure you want to do that?')
ifTrue: [self inform: 'go for it'.
count := -1000]]
ifFalse: [count := count - 1]
I have to admit, this is really impressive. And, once I figure out how to do this via ajax, it will be even more so. Andiamo!
- Read the parts of the documentation dealing with creating basic HTML pages - I referenced then in a previous post. The explanations are quite clear, and, for me, helped to demystify the system.
- Read the tutorial A Walk on the Seaside. Although the HPI tutorial is much more comprehensive, I found this one much easier to understand.
- Go through the 'tests' section in the Seaside code. I.e., when you have the website running, navigate to the Tests section and go through each of the tests e.g. WAButtonTest. Make sure you use the Toggle Halos option and have a look at the code - typically the renderContentOn: method. This will really help you connect the code with what it does on screen.
- Remember to click the '?' in the Squeak browser. I only just stumbled across all the class comments. I don't know why I didn't do this before, but I think I was looking for the comments in the classes themselves. Perhaps that is how it worked in an earlier version? Anyway, the class comments help a lot
self attributes at: 'summary' put: aString
This is useful for reading the code. With: contains the code that will go between tags and everything else is likely to set the tags attributes.
html tableCaption: 'blah blah'
And that suddenly struck me as odd. The tag is being generated by the WAHtmlCanvas object rather than by the table tag object. That would make sense if the tag could live outside of the table, but I don't think it can.
I don't think this is a problem, it's really more of a design question. I wonder why they built it like this. I feel a question to the beginners' list coming on!
summary: 'This table gives the character entity reference,
decimal character reference, and hexadecimal character
reference for 8-bit Latin-1 characters, as well as the
rendering of each in your browser.';
html tableCaption: 'HTML 4.0 entities'.
self renderEntityTableColumnGroupsOn: html.
self renderEntityTableHeadOn: html.
self renderEntityTableFootOn: html.
self renderEntityTableBodyOn: html]
It looks reasonably straight forward, but I had a couple of questions
- what was the summary: item?
- and why did we need the with: block?
But what about the with: block? The reason I was pondering on this was that it seemed redundant. Why not send all the messages directly to html and self? And, this is where it all gets a bit messy - although in retrospect it is all very easy to understand. I used a method finder to locate the implementors of table, and started looking at it. My initial thought was that html table would return a WAHtmlCanvas tag (not sure why I thought that), but it turns out that although table is defined in that object, it actually returns a WATableTag. And... the tag has a 'closed' property. I think that determines whether the tag is rendered as
Another bit learned ;-)
Now, I must be honest and say that I don't fully understand what Kent is talking about - yet. However, it is interesting to see some of the Smalltalk jargon put into a new context, and I am finding that really helpful. However, what really caught my eye was this sentence.
The other advantage of code written to reveal intention and conceal implementation is that it is much easier to refine by inheritance..
This highlights the problem I have been having. I am always trying to understand the implementation, instead of focusing on the intention. Now, clearly, if you are learning a new language, looking at implementation is important - if only to pick up coding style - but I am slowly beginning to understand that productivity in Smalltalk comes - at least in part - from treating objects as black boxes, and relying on understanding the intention.
in other words, you program with the assumption that the object does exactly what it says on the label. I am going to try that as an approach and see if it helps to clarify things.
I have asked a question about this on the beginners list.
Randal Schwartz replied - almost immediately - and said
Clearly, position is an instance var, or perhaps a temporary. An instance var
may or may not have accessors, depending on whether it is meant to be tweaked
from the outside. #menuComponent, on the other hand, may be just an accessor,
or it may be a whole pile of code to generate that menu on the fly. At this
point, it doesn't matter.
Whether internal accesses to instance vars should use accessors instead of
direct access is a subject to debate (read: religious war). I hope you
haven't accidentally triggered that thread here. I tend to do the simplest thing that works, and leave it at that.
I totally agree with the simplicity principle. I can see why always accessing properties via getters would result in a consistent experience, i.e. the returned value would be the same whether the inquiring code was internal to the object or another object. However, it seems like more work.
There again, if you have gone to the trouble of establishing getters, perhaps one should use them everywhere. I will have to think about this.