Smalltalk’s not dead, it just needs a facelift

Its a sad but true fact that perception is reality for most of us. Unfortunately this means that looks matter. Most Smalltalk UI’s look like hangovers from Windows 3.1 (or in Squeak’s case, Toys R Us). Folks may moan about Swing being complicated, but the complexity and abstractness of the framework gives it incredible flexibility, beyond that of .Net winforms.

I fear Smalltalk will remain marginalised until its possible to build UI’s of the quality and responsiveness of IntelliJ IDEA with it.

I’m waiting for Pollock – the next generation UI framework for VisualWorks. The bar is high. I hope it makes it.

Threads in Smalltalk

Looks like I opened a can of worms!

Part of the impetus for my investigation into Smalltalk’s threading model was running BottomFeeder on OS X. The UI seems to lock up on my machine when retrieving feeds (or possibly posts – I forget). I don’t see the ‘wristwatch’ that a completely frozen smalltalk UI shows in OS X, but all the scroll bars seemed to stop working, and it appeared to queue up all my mouse clicks so that all manner of crazy things happened when the UI came back 🙂 This may have contributed to my initial impression that any blocking IO would block the whole smalltalk process.

That’s more of an aside (although if anyone knows whether BottomFeeder does indeed have this problem on OS X that would be great!). (Later: James kindly responded – it is a known issue in OS X and should improve)

What interests me more generally is how well smalltalk deals with things like high concurrency. Is it possible to implement non-blocking IO? Is it even necessary – can I just fork off an unlimited number of Process objects? Would it be feasible for example to use smalltalk to build a web server that gracefully survives a slashdotting on a powerful commodity pc?

For example with the latest release of Java you might use the nonblocking IO library and one thread per cpu, keeping all the cpu’s maxed out without thread-switching, so your only bottleneck is available memory (and browser timeouts). Is there an idiomatic smalltalk equivalent?

My usual tactic for maximising throughput is to minimize the number of thread/processes running, and only hand off to another process when you would otherwise have blocked, for example on IO. Nonblocking IO support in java allows me to use just one thread for all an application’s network IO, and keep the rest of the threads as busy as bandwidth allows. I don’t know how to do this in smalltalk, nor even if I’m worrying about the right problem in smalltalk 🙂

Smalltalk IO

Continuing on my own personal Smalltalk Renaissance, I spent some time investigating threading, IO, and general long-running operations. First a small rant. There is a woeful lack of documentation out there on how threading works (or doesn’t) in Smalltalk. The stuff I did find did not fill me with confidence, as it seemed to indicate that Smalltalk was inherently single-threaded, and thus crippled when it comes to doing network IO. In the end I decided to just try it. This is what I came up with:

| httpClient request response |
httpClient := HttpClient new.
request := HttpRequest get: 'http://www.cincom.com'.
Transcript show: 'Before Request'; cr.
response := httpClient executeRequest: request.
Transcript show: 'Request Complete'; cr.
Transcript show: response body decodedValue.
Transcript show: 'After Request'; cr.

Sure enough, the whole environment froze while waiting for the request to complete. Game over.

Then I finally decided to actually look at the core libraries, and happened upon the BlockClosure class, with the promising looking ‘fork’ method. Hmm. My second attempt looked like this:

| httpClient request response |
httpClient := HttpClient new.
request := HttpRequest get: 'http://www.cincom.com'.
Transcript show: 'Before Request'; cr.
[
response := httpClient executeRequest: request.
Transcript show: 'Request Complete'; cr.
Transcript show: response body decodedValue.
] fork.
Transcript show: 'After Request'; cr.

Note the addition of the [ ] around the code that actually hits the network. This denotes a block, which is in fact an instance of BlockClosure, which brings the ‘fork’ method call into play. Sure enough, the second attempt did not freeze the whole environment, and I saw ‘Before Request’ immediately followed by ‘After Request’ in the system transcript. Shortly followed by the html from Cincom’s homepage.

Smalltalk rocks.