Path: utzoo!attcan!uunet!zephyr.ens.tek.com!tekcrl!tekgvs!jans From: jans@tekgvs.LABS.TEK.COM (Jan Steinman) Newsgroups: comp.object Subject: Re: "Sender" construct in OOLs Message-ID: <6145@tekgvs.LABS.TEK.COM> Date: 13 Oct 89 21:56:07 GMT Distribution: comp.object Organization: Tektronix Inc., Beaverton, Or. Lines: 62 As Joshua Susser pointed out, it is trivial to do in Smalltalk. His description is quite good, and points out something that many of the C++ people who have been discussing its difficulty of implementation might have missed: the sender is identified in the calling stack, and so is simple (although non-portable) to obtain. An in-line assembly code #define aught to do it. The bigger question seems to be what is it really good for. I've put it to *considerable* use in Smalltalk, for mutual recursion as well as other reasons. It is also invaluable for use in a debugger. (Do you know how long it takes gdb to print a C++ symbolic stack backtrace on a large application! Hint -- it's coffee time! Tenths of a second typical in Smalltalk.) Another good use is to elimnate infinite recursion when recursively traversing cyclic graphs -- simply look back the sender chain to see if "self" (or "this") is back there anywhere. (Keeping a flag around to do this is non-reentrant.) Another place I've used it was as a "port manager", for controlling a number of multiplexed devices from a single RS-232 port. Client objects would "register" with the port manager, who determined their identity through "thisContext sender receiver". Client objects would simply "read" or "write" without passing arguments, and each time, the manager discovered who they were and tacked on the proper MUX address. I find "obj read" or "obj->read()" much more clean and readable than "obj read: self" or "obj->read(this)". In short. I think this is one of the best-kept secrets in Smalltalk. It doesn't appear to be used outside of the debugger in the standard image. I've added numerous general purpose methods to "thisContext" make more use of "sender", here's an example: (C++ implementation left as an exercise to the reader! :-) !ContextPart methodsFor: 'testing'! isRecursive "Does the sender's receiver, method, and arguments appear previously in this context? Will this context infinitely recurse?" | ctx rcvr meth | ctx _ self home. rcvr _ self receiver. meth _ self method. [(ctx _ ctx sender) == nil] whileFalse: [ctx _ ctx home. "Optimization: skip intervening contexts." ctx method == meth and: [ctx receiver == rcvr and: [self home argsMatch: ctx and: [^true]]]]. ^false! argsMatch: aContext "Are the arguments passed to the receiver and identical?" self argCount = aContext argCount ifFalse: [^false]. 1 to: self argCount do: [:i | (self basicAt: i) == (aContext basicAt: i) ifFalse: [^false]]. ^true! ! Jan Steinman - N7JDB Electronic Systems Laboratory Box 500, MS 50-370, Beaverton, OR 97077 (w)503/627-5881 (h)503/657-7703