Sunday, September 13, 2009

Message passing

I'm working on a primitive message-passing mechanism to allow objects to request that other objects execute methods on demand. Sort of a remote procedure call, you might say. The basics are as follows:
  1. Every object which inherits from Carrot::Universal has a 'children' slot and a 'rpc_ok' slot. The first stores a reference to every object that the present object "owns", or has created. The second is a list of methods in the present object which are allowed to be called by this mechanism.
  2. There's a 'pass' method, which creates a standard Carrot::Msg object and uses it as an argument to the 'catch' method of each object in the present object's 'children' slot.
  3. The message created by 'pass' has a hashref instead of a string as its content. This hashref contains
    1. The caller object's classname
    2. The intended recipient class's name (will be matched as an ending regex, not a strict string equivalence, so 'Lexer' will work as well as Carrot::Lexer)
    3. The method to be called
    4. Arguments to the method
  4. If the recipient classname matches the name of the called object, and if the given method is on the recipient's 'rpc_ok' list, then thy will be done.
  5. Matching or not, the recipient object will pass the message on to all of its children.
Why? This is the mechanism that lets (definitely some, possible all of) the pragmas work. In the new design, the level at which pragmas are recognized (the Parser) is, for instance, 2 levels removed from where markup characters are tokenized as such (the Tokenizer). The possible solutions were
  1. to implement a custom pass-along method for EVERY method that ends up being at greater than one remove from where it ends up being needed
  2. to pass handles to objects to all other objects (AKA "the last design, to an extent")
  3. to implement a generic message passing mechanism
The last one seems cleanest, most maintainable, and most useful in the long-term to me.

No comments: