It's wonderful that the Squeak sources are fully open and easily browsable. But even more than that, Squeak's runtime is open to browsing (and possible modification) through introspection.
Normally introspection is reserved for things like Debuggers, but here's a case where I used the facility to my advantage:
I needed to FTP a fairly large file from a server. Since I was working in Squeak at the time, I figured I would do the FTP in Squeak, writing out the contents to a file when it was complete. A couple minutes later, after browsing the FTPSocket sources, I had an FTP process running in the background.
After it had been running for a bit, I realized that it would be nice to have some sort of visual indication of the FTP progress. However,
a) I didn't want to clutter up the existing FTPSocket code with a progress display (*), and
b) I didn't want to stop and restart the transfer, in any case.
Looking again at the FTPSocket sources, I discovered that what I wanted was the position of the stream stored in the temporary variable 'response' in the method #getAllDataWhileWatching:
Since *everything* in Squeak is an object, including the runtime contexts of the various running processes, I was able to do the following on the already running ftpProc:
ctxt := ftpProc suspendedContext. [ctxt method == (FTPSocket compiledMethodAt: #getAllDataWhileWatching:)] whileFalse: [ctxt := ctxt sender].
This followed up the ftpProc's context chain until it found the context which was executing in the #getAllDataWhileWatching: method. Then, to get the value of the 'response' temporary variable in that context, I executed:
resp := ctxt tempAt: (ctxt tempNames indexOf: 'response').
Then all I needed to do was periodically send 'position' to the resp stream to find out how much data had been transferred:
oldSize := newSize := 0. 'FTP status:' displayProgressAt: (Display width - 96) @ 64 from: 0 to: ftpSize during: [:bar | oldSize := newSize. newSize := resp position. [oldSize ~= newSize] whileTrue: [bar value: newSize. (Delay forSeconds: 30) wait]].
(*) after succesfully doing this, I started thinking about the user-interface ramifications of String>>displayProgressAt: It's a handy thing, but it puts the user at the whim of the person who coded it in, and since it is statically associated with the method, rather than some dynamic form of progress display control, if it isn't what the caller wants displayed, it can't easily be modified. For example, the recent suggestions that the automatic server update progress show the progress of the entire transfer, rather than the individual streams.
I wonder if some form of dynamic registry for progress indication, perhaps something like how error handling is registered, might be something to explore.
-- tim
squeak-dev@lists.squeakfoundation.org