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.