Saturday, September 27, 2003

Nifty Trick...

OK, in my MS Agent Remote Control program I needed to record the actions that one can do to the agent object. I have an agent object that wraps the COM object. Here's an example of a public method that does some action that I need to be able to "record" and playback:

    speak: aMessage
      self triggerCommandEvent.
      self control speak: aMessage

Now, self control returns the COM object. The method: #triggerCommandEvent is where things get interesting, though. Every method that needs to be recorded and played back calls this method first thing. Now, here's the implementation of the #triggerCommandEvent:

      | stackFrame |
      stackFrame := Processor activeProcess topFrame sender.
      self triggerCommand:
          selector: stackFrame method selector
          arguments: stackFrame arguments)

This method is very interesting in that I don't have to have a specific piece of code in every method that wraps their parameters and name. Now, I have one method that I simply call and it walks up the stack picks off the information for me and then, wraps it in a Message object that can be used to call this object again. Now, notice that I didn't specify "self" in the message. It's because the message might not be coming back to me. There's an object that records these "actions" and call it a tape. This tape can be "played" back on any object. So, when you're playing with the agent and press "play". It plays back the "tape" on the agent object. But, what happens when you want to output the script? Well, I created another object that has the same public protocol (interface if you will) as my agent object. Now, we simply play the tape back on this object and the "script" object writes out JavaScript code instead of triggering actions on the agent.

The thing I like about this is that there are several ways to do this, but being able to walk the stack allows you to do some rather elegant things and some less typing...=) Now, the above code is different in every Smalltalk, but you can do it. You can even do this concept in most dynamic languages. I know this isn't the greatest show of Smalltalk's abilities, but it's one of those things that I thought was nifty.

No comments: