Path: utzoo!utgpu!news-server.csri.toronto.edu!clyde.concordia.ca!uunet!tut.cis.ohio-state.edu!zaphod.mps.ohio-state.edu!mips!apple!oliveb!tymix!lobot!roberts From: roberts@lobot.Tymnet.COM (Michael Roberts) Newsgroups: comp.lang.c++ Subject: Message dispatching Message-ID: <3550@tymix.UUCP> Date: 9 May 90 02:29:29 GMT Sender: usenet@tymix.UUCP Organization: BT Tymnet, Inc.; San Jose, CA Lines: 125 Appologies if this has been covered or is particularly brain damaged. ----Synopsis: C++ seems ill-suited to handling a certain type of message passing. An example is presented. A possible extension to C++ is offered. Hopefully someone can point out an easier way that presently exists! (Power readers may skip down to "----Extension to C++") ----Overview (real-world motivation): I have a database of objects (all members of classes derived from a common base class). Some of these objects are members of a text class. That text class has methods to respond to editing messages. Also in the database are version class objects. Version objects each contain a pointer to a text class object, as well as data and methods for responding to versioning commands. My application uses version class objects to provide the interface to the text class objects, and so protect them from arbitrary editing which does not adhere to versioning standards. The natural impulse would be to say that since a version (pun intended ;-) class object contains more information than a text class object, and since we want the version class object to inhibit, override or modify the behavior of the text class object it points to, let the version class be derived from the text class, with "virtual" methods in the text class. The problem is that there are many different classes besides the text class that version class objects can "contain" (point to) and hence protect. I do not want to have distinct version classes derived from each of those myriad classes; I want a single version class to handle all such buffering. ----My present ugly solution: The version class performs protective services that amount to message routing and manipulation. I have achieved this via a laborious process of duplicating each and every message that a contained object can respond to with a like-named method in the version class. Almost all these version methods are identical in basic form: they check and update certain version data, then if conditions are met, send the appropriate editing message to the contained object. By design, that message always has the same name as the version method itself. ----Extension to C++: default methods What I think I want is a mechanism for imitating late binding in C++, that operates outside the boundaries of inheritence. (I hear the groans already...) Consider the following scenario. Let the version class be independent of the other classes. Let it have one or more public methods called default. This would include default(...), and possibly overloaded alternatives such as default(int). The compiler would then resolve all calls to unidentifiable methods in the version class as calls to these default methods. The new semantics (and the compilier that reads it) would have to solve the following problems: - identification of the actual method called - simple branching logic based on that identifier - means for calling a method with that same name for another object - means for returning the return value from that chained call To identify which method is actually being called, a special function would be made available inside the default methods (only): default(). That routine would return a pointer-to-function. The achievement of simple branching logic would require allowing switch and case statements to accept such pointers. To pass the original arguments that were in the incoming call to the outgoing call (if desired) and to return whatever it is that that outgoing call returns, we might use the following (incomplete) scheme: class version { private: data* pObj; // pointer to "contained" object public: // various explicit methods... default default(...); } default version::default(...) // returns whatever it should!!! { switch (default()) // default() returns int to match { // cases of the following style: case version::whatzit: // equivalently, just "case whatzit:" //... // perform some desired side effect return; // whatzit NOT allowed to call through case version::foo: // Might read variable length arglist and do something particular // to this call, perhaps changing, removing or adding an argument. char c = 'b'; return pObj->default(c); case version::bar: // Might even change call entirely: return someOtherPointer->someOtherMethod(someOtherArg); default: // its usual meaning: unknown case return pObj->default(...); // call "passed through", WITH ARGLIST } } main() { char c = 'a'; version v; v.foo(a); // ends up calling some Obj.foo('b'); } It might be that such constructs are useful for other purposes, such as pre- and -post routines to place around some methods in a class. So, the questions are... - Does C++ already provide other mechanisms to do what I need? - Has someone else already suggested this? - Does anybody out there like the basic intent of what I am suggesting? - Is there a better way, or a more general way to express this? To those of you who got this far, THANK YOU for your kind attention! -Mike ---- Mike Roberts (roberts@rocky.tymnet.com) (408) 922-7931 Holding down my end of the bell curve... whichever end I'm on at the moment.