Boost logo

Boost :

From: Matthew Vogt (mvogt_at_[hidden])
Date: 2004-03-04 17:49:16


scott <scottw <at> qbik.com> writes:

> On Behalf Of Darryl Green
>
> > I've tended to think of the tightly/early bound, just queue a functor,
> > and the message passsing + switch case as 2 completely independent
> > patterns, but maybe they should be built on a common framework (at a
> > level above the detail that they both ivolve queuing some sort of
> > object).
>
> Yes. I agree with your distinguishing of the two forms. There is some
> relief to be found in that.
>
> While I can acknowledge the existence of async messaging where the
> sender has type knowledge of the receiver, I also think its dangerous.

In what way do you think it is dangerous? Provided that the type knowledge
is correct, then it merely provides an assurance to the sender (which they
may or may not care about) that the recipient claims to deal with a
particular type of message.

(and a small opportunity for optimisation based on the type knowledge)

> Given the two approaches, most developers head down the "fake method"
> route. This inevitably results in receipient-type knowledge and that
> precludes some really cool active objects (please refer to other
> messages if this fails to allude to anything).

Are you referring to the 'forwarding proxy' example (proxy in an object
sense, not a method sense)? This could be done with a method interface, but
it would a maintenance nightmare :)

Actually, I think this could be done, but in a different way to the
message-only version. An object of the proxied type would still have its
method stubs invoked to create fully-bound functor messages, but those
messages would be queued to a different object - the one that would forward
these (essentially typeless) messages on to the real object recipient.

The difference would be in the proxies - they would bind to member function
addresses, but not on the current instance, and they would enqueue the message
to a non-local queue.

> Also I think its right
> to say that there is nothing method-based that cant be done message-
> based; but is the converse true?

Given that messages would provide the implementation of the method emulation,
I agree. I suspect the converse may be true, but it might take a lot of
(unrewarded) effort...

> There is some more fundamental reason why message-based is right that
> is probably rooted in theory (sets?). There has to be good reason why
> protocols are so "right". Everyone appreciates the content of RFCs and
> telephony signaling specifications but we persist with method-based
> messaging.

But a method-based interface would still be implemented as message-passing.
How can an underlying mechanism have fundamental advantages over something
which is layered above it?

> <sigh> Its an area of personal wonder.
>
> > The AO pattern doesn't require that you identify the object
> > you want to
> > invoke the method on in the proxy, because you send the proxy to that
> > object, and only that object. So one could drop the "this" parameter
> > from the proxy. That would potentially allow the proxy to be
> > routed/forwarded in a more general reactive object model (I think this
> > was one of Scotts requirements)?

I don't think that I've really followed this. The active object pattern
specifies that there may be many identical servants servicing method requests
concurrently, but this implies that the servants can't be stateful. I think
this is a special case, as far as rective objects are concerned.

> > I'm not 100% sure how useful this is,
> > but it might be nice for the class of problem where you do want
> > concurrent execution - of as many completely independent instances of
> > the object as is "useful". The client/master doesn't care
> > which instance
> > - the next available one will do nicely.
>
> IIUC, this is a de-generate form of interaction that has been touched
> on previously. At least in my work it imposes an unacceptable design
> constraint;
> there needs to be some identification of the receiving active object.
> Most significantly (?) there could not be multiple servants per scheduler
> (i.e. thread).
>
> > is. Perhaps its interface can be made more generic to allow its
> > operation to be policy based. Broadening the definition from "return
> > value" to "message delivery notification" with the sender supplied
> > message delivery notifier object passed the return value from the
> > handler doesn't feel too weird to include at the low level, and
> > shouldn't cost anything for a void return without notification.
> > Interestingly, the option to generate a a notification that a message
> > with a handler returning void has been processed doesn't seem like a
> > strange feature when looked at this way (a void future is a bit odd
> > though).
>
> Followed everything up to the point where you start discussing "return
> values". On one hand you do discuss this as simply another message. OTOH
> you do persist with some method-based concepts. Maybe this is not
> significant.

Return values can be seen as a syntactic nicety. In implementation then it
is just another message, but if a sender knows that the logical outcome of
the processing of the message he is sending will be another message received
from the other object, then you can remove two switches by binding both
the addresses. This would particularly be of benefit if a message had
dynamic dispatching, where a different handler was invoked depending on the
current state of the receiver.

Aside: the void future was a consequence of wrapping active behaviour around
'normal' object interactions. Say you had the following interaction:

struct Engine {
  enum State { Idle, Running };
  State state;

  Engine() : state(Idle) {}

  void start(void) { state = Running; }

  State get_state(void) { return state; }
};

struct Controller {
  Engine& engine;

  Controller(Engine& e) : engine(e) {}

  void begin(void) { engine.begin() };
}

int main(int, char**) {
  Engine engine;
  Controller controller(engine);

  controller.begin();
  assert(e.get_state() == Engine::Running);
}

This would be fine if all objects were normal objects with synchronous
behaviour, however, if the Engine and Controller were wrapped to become active,
then there would be no guarantee that Controller::begin() would be processed
before Engine::get_state(), unless the caller of Controller::begin() was forced
to wait for the processing of that message to complete before continuing.

I don't think a void future has any relevance for objects which are designed
to be active.

Matt


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk