
scott <scottw <at> qbik.com> writes:
Hi Matthew,
Hopefully my recent message (new subject "Reactive Objects") clears the air.
Yup. I'll reply to that when I've read a couple more times... :)
Yes. Although, the sender could bind a return address into the call in this model also - it would have to be the address of a method in the sender. This would allow the automatic routing that I think is preferable to messages. This model is still working by passing messages, mind, but the messages have extra data with them to skip the dispatch processing.
Hmmmmm. We are either still confused or we have different targets. Since I exist in the former continuum, the following is mostly for me.
If there were a callback (called by thread after de-queueing a message) that went something like;
db_client::on_next( ... ) // User pressed the "next" button { if(db_server.next( current_record ) == END) { // Wrap to the beginning db_server.first( current_record ); } }
How do you "bind a return address" to the point just after the "call" to "db_server.next"? Even if you do manage this syntactically, is the call to "on_next" suspended somehow? Obviously the same "suspension" would have to occur for the call to "db_server.first".
You can't (as far as I know, anyway). So the return address has to be a method in the object that invoked the call. The client has to be refactored to (pseudo-code): db_client::process_next( ... next_record ) { if ( next_record == END ) { // Wrap to the beginning return_to( process_next ) = db_server.first( current_record ); } else { ... // do something } } db_client::on_next( ... ) { return_to( process_next ) = db_server.next( current_record ); } This assumes that the return_to<> proxy can be created to update the other proxy (the method request emulator) to bind the return address...
I suspect that you are thinking (and have been doing your best to tell me) that the "asynchronous calls" will be effected by the threads in each active object. They will simply "chain"?
Not sure what you mean by 'chain'...
If that is the case then I see some difficulties. The least would be the loss of throughput relative to "true" async calls. More importantly I think you might be calling back into an object (e.g. the db_server calling a response method in a client) that otherwise has no idea that the original request has been completed. As a "model of operation" this seems at least as foreign as the "fully async" model that SDL pushes?
I don't think I mean what I think you think I mean. Taking away the proxies, the above pseudo-code would become: db_client::on_next( ... ) { //return_to( process_next ) = db_server.next( current_record ); message m; m.sender = this; m.address = bind(&db_server_class::get_next_record, db_server); m.arg1 = current_record; m.return_address = bind(&db_client::process_next, this); db_server.enqueue_message(m); } and the underlying message_handler code (from which both the db_client and db_server_class classes derive) looks like: message_handler::process_message_queue() { message& m = dequeue_message(); // client request if ( m.return_address ) { message result; result.sender = this; result.address = m.return_address; result.arg1 = m.invoke(); m.sender.enqueue_message(result); } else { m.invoke(); } } In both cases, the objects are merely dequeueing messages and doing whatever processing the message requires, possibly generating other messages as a result (directly, as a return message, or indirectly as a side effect). Therefore, it is fully asynch. The 'method request' interface is only being used in the creation and binding of messages.
In your version of things the sender is selecting the code to be executed in the recipient. This is the fundamental difference. In my version the client cannot assume anything about the receiver. There are perfectly valid examples of "active objects" in my ActiveWorld that _must_ be able to receive _anything_. One example is a proxy object that accepts any message and forwards it across a network connection to an active object in a remote process.
Yes - I was assuming a published interface from the (re)active objects, although you do present a good example of somewhere this can't be done. For this individual case, you can ditch the method-emulating proxies and deal with the underlying message queues directly.
Also, the active object may (or may not be a state machine. The sender (i.e. a client) cannot truly know which method to call as the correct method is state-dependent. The runtime switch issue that exists for this circumstance is similar to the issue that exists for selection of method call vs switching on message. One strategy involves knowledge of the recipient, the other doesnt. Well, other than that all active objects are capable of receiving messages
I hadn't realised how integral the state machine was to your design until I read your other post. Still, if you are doing dispatch on both message code and object state, it can be simplified to bind the message to a per-message code dispatch function which then dispatches on object state. Matt