[comp.object] "Sender" construct in OOLs

time@oxtrap.oxtrap.UUCP (Tim Endres) (10/05/89)

Back in 1984, I suggested to Apple that they adopt an extension to
Clascal (what is now called Object Pascal). This extension would be
much like the "SELF" keyword, except that it would reference the
sender of the message. In other words, SELF refers to the object that
received the message, and SENDER would refer to the object that sent
the message.

At the time, I needed a mutual recursion between two objects, and did
not like the fact that I had to pass the second object as a parameter
in the message. Apple never responded to this request. Neither did
Computer Language magazine, who refused to run the article I had
written proposing the construct be given consideration in new OOLs.

Does anyone know of a specific OOL implementation of SENDER?
Any good reasons why it should not be included?

dchapman@portia.Stanford.EDU (David Chapman) (10/05/89)

In article <TIME.89Oct4131658@oxtrap.oxtrap.UUCP> time@oxtrap.UUCP writes:
>Does anyone know of a specific OOL implementation of SENDER?
>Any good reasons why it should not be included?

I can think of only one reason that _some_ languages wouldn't be able to
support a "sender" construct: the sender might not be an object at all.
I don't know anything about Object Pascal, but in C++ the sender might
be a function instead of another object.

Mutual recursion between objects sounds kind of obscure (I use it only
in compilers).  If it's not going to be used often, a language developer
isn't going to want to support it.  It's also difficult to add new
keywords to existing languages because you invalidate any existing code
that happened to use that keyword as an identifier.

Can you tell us more about what you were trying to do?  Is this
something that everyone would want to use?

jima@hplsla.HP.COM (Jim Adcock) (10/06/89)

You should be able to do this using function call overloading in C++.
I suspect its not trivial to figure out, however.

dchapman@portia.Stanford.EDU (David Chapman) (10/09/89)

In article <9450008@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
>You should be able to do this using function call overloading in C++.
>I suspect its not trivial to figure out, however.

After thinking about this some more, I cannot conceive of a way to
implement the "sender" construct.  Why?  Because the "sender" is of 
arbitrary type.  *Anything* can send an object a message.  That's the 
whole point.  Maybe Smalltalk or Flavors could handle this by looking 
up the type of the object, but it would be horrendous to do in a 
compiled language like C++.

Comments?  Remember, the original poster wanted mutual recursion - he
wanted to send messages back to the caller.

jima@hplsla.HP.COM (Jim Adcock) (10/10/89)

>dchapman@portia.Stanford.EDU (David Chapman) /  3:40 pm  Oct  8, 1989 /
>In article <9450008@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
>>You should be able to do this using function call overloading in C++.
>>I suspect its not trivial to figure out, however.
>
>After thinking about this some more, I cannot conceive of a way to
>implement the "sender" construct.  Why?  Because the "sender" is of 
>arbitrary type.  *Anything* can send an object a message.  That's the 
>whole point.  Maybe Smalltalk or Flavors could handle this by looking 
>up the type of the object, but it would be horrendous to do in a 
>compiled language like C++.
>
>Comments?  Remember, the original poster wanted mutual recursion - he
>wanted to send messages back to the caller.

What I was thinking of is that a sender class overloads its function call
operator to push the sender "this" onto a stack as a prolog, 
and pop that "this" as a postlog in the sender function call operator 
overloading.  If no sender class method had been called, then the stack
of "sender this's" would be empty.  IE "a null sender."

Likewise the receiver class function call operator could be overloaded
to get a copy of the sender "this" from that stack and interpret it as
"sender", adding sender as a parameter to the underlying function call.

I suspect this approach would be painful to actually do in C++, since
each distinct set of function parameters requires a seperate overloading
of the function call operator, and since the receiver functions must
themselves be defined as objects of some class, so that operator(something)
can be applied to them.

Still, an object of a class not obeying the sender protocol could send a message
to a receiver, thus the receiver would find an incorrect sender on the stack.
But such a protocol-ignoring object would do its dirty work either within 
a sender method, in which case it could be considered a delegate of the sender,
or outside all sender methods, in which case the stack would be empty, and the
receiver would note that "no" sender sent the message.

An alternate approach is for both sender and receiver to implement these
protocols by overloading operator->, and require that any messages sent
to either sender or receiver be via "->" as opposed to "."  Operator->()
seems easier to use as opposed to operator(this, that, ortheotherthing) since
there aren't parameters to operator->().  On the other hand, operator->()
never regains control after method dispatch, so sender functions would have
to explicetely unstack their "this" [which is the receiver's "sender"]
before exiting.

For mutual recursion, either sender and receiver can be written as the
same class, or you can use multiple inheritence to "glue" together both
a send/receive capability in a mutual subclass -- assuming sender and
receiver are written orthogonally.

andreasg@boulder.Colorado.EDU (Andreas Girgensohn) (10/10/89)

In article <5677@portia.Stanford.EDU> dchapman@Portia.Stanford.EDU (David Chapman) writes:
>In article <9450008@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
>>You should be able to do this using function call overloading in C++.
>>I suspect its not trivial to figure out, however.
>
>After thinking about this some more, I cannot conceive of a way to
>implement the "sender" construct.  Why?  Because the "sender" is of 
>arbitrary type.  *Anything* can send an object a message.  That's the 
>whole point.  Maybe Smalltalk or Flavors could handle this by looking 
>up the type of the object, but it would be horrendous to do in a 
>compiled language like C++.
>
>Comments?  Remember, the original poster wanted mutual recursion - he
>wanted to send messages back to the caller.


In Lisp one could do it with a variable with dynamic scope:

(defvar sender :no-object)

;;; within every method:

(let ((sender self))
  ;; message body (actually, the previous value of sender is needed within
  ;; the body)
)

There are no variables with dynamic scope in C.  A solution could be
an array as a stack of senders (I don't no the C++ syntax).

object *senders[200];
int    senders_top = 0;

senders[0] = (object *)NULL;

/* within every method: */

senders[++senders_top] = self;
/* message body */
senders_top--;

susser@apple.com (Joshua Susser) (10/11/89)

In Smalltalk-80, it is possible to get a message's sender by evaluating

    thisContext sender receiver

or something close to that.  *thisContext* is a pseudovariable that binds 
to the MethodContext for the current activation record. The *sender* 
message answers the calling (or sending) context of *thisContext*, and 
*receiver* returns the *self* binding for that context. It's been about 
two years since I played with this stuff and I don't have ST80 handy, so I 
could have missed something here.  And ParcPlace could have changed things 
since then.

Also, I believe that Smalltalk/V-PM has a *self sender* construct that 
returns the sender object.  They were going to just make up a *sender* 
pseudovariable, but George Bosworth said he was worried about creating 
another reserved word; I think they should have gone for it.

I think using a *sender* construct for mutual recursion could be a little 
messy. I prefer passing the argument explicitly.  The place where I think 
it is most useful is to discriminate between internal and external
invocation of a message.  This allows private messages, protection, etc.

No objects in my eyes, just dust from Bourbon St.

Joshua Susser                                        Apple Computer ,Inc.
Object Percussionist                            Advanced Technology Group
arpa: susser@apple.com                        20525 Mariani Ave. MS 76-2D
uucp: {sun,nsc,...}!apple!susser                      Cupertino, CA 95014
ALink: susser.j                                              408/974-6997

I beat on objects.

alonzo@microsoft.UUCP (Alonzo Gariepy) (10/12/89)

In article <9450013@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
> >dchapman@portia.Stanford.EDU (David Chapman) /  3:40 pm  Oct  8, 1989 /
> >In article <9450008@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
> >>You should be able to do this using function call overloading in C++.
> >>I suspect its not trivial to figure out, however.
> >
> >After thinking about this some more, I cannot conceive of a way to
> >implement the "sender" construct.  Why?  Because the "sender" is of 
> >arbitrary type.  *Anything* can send an object a message.  That's the 
> >whole point.  Maybe Smalltalk or Flavors could handle this by looking 
> >up the type of the object, but it would be horrendous to do in a 
> >compiled language like C++.
> >
> >Comments?  Remember, the original poster wanted mutual recursion - he
> >wanted to send messages back to the caller.

I think the problem here is an attempt to create general language support
for a non-general problem.  Many of the ideas expressed here do not
reflect the best modular design.  It is up to an object to define its
public interface; it is not good for the sender's address to be obtained
without its consent.  The provision of this address should be part of
an explicit protocol between sender and receiver.  In a type safe language
such as C++, this should be done by passing a typed pointer to the
receiver.

You are looking for some syntactical sugar to support a non-general and
questionable practice.  The basics of modular object-oriented design
favour classes that respond to messages and act upon their own state.
If an object is going to communicate with an instance of some other
class, that knowledge should be part of its state, not just some transitory
relationship to a particular sender that exists during the invocation of
some method.

Remote Procedure Calls and various other kinds of delegation and proxy
(such as iterator objects that send some message to all the members of
some collection on your behalf) should not have to cope with this concept
of sender.  I understand the utility of the features being discussed, but
they do not merit general support.

Alonzo Gariepy				// my opinions, not necessarily
alonzo@microsoft			// those of Microsoft

jpd00964@uxa.cso.uiuc.edu (10/12/89)

/* Written  5:09 pm  Oct 11, 1989 by alonzo@microsoft.UUCP in uxa.cso.uiuc.edu:comp.object */
In article <9450013@hplsla.HP.COM> jima@hplsla.HP.COM (Jim Adcock) writes:
>> >After thinking about this some more, I cannot conceive of a way to
>> >implement the "sender" construct.  Why?  Because the "sender" is of 
>> >arbitrary type.  *Anything* can send an object a message.  That's the 
>> >whole point.  Maybe Smalltalk or Flavors could handle this by looking 
>> >up the type of the object, but it would be horrendous to do in a 
>> >
>> >Comments?  Remember, the original poster wanted mutual recursion - he
>> >wanted to send messages back to the caller.
>
>I think the problem here is an attempt to create general language support
>for a non-general problem.  Many of the ideas expressed here do not
>reflect the best modular design.  It is up to an object to define its
>public interface; it is not good for the sender's address to be obtained
>without its consent.  The provision of this address should be part of
>an explicit protocol between sender and receiver.  In a type safe language
>such as C++, this should be done by passing a typed pointer to the
>receiver.

The sender must still pass its address which means that it must allow someone
else to be able to access its instance variables at the called objects will.

>You are looking for some syntactical sugar to support a non-general and
>questionable practice.  The basics of modular object-oriented design
>favour classes that respond to messages and act upon their own state.
>If an object is going to communicate with an instance of some other
>class, that knowledge should be part of its state, not just some transitory
>relationship to a particular sender that exists during the invocation of
>some method.

That may be the theory, but not the practice in Obj-C on the NeXT.  A sender
is actually encouraged as that limits the amount of irrelevent information sent.
A sender is a very very powerful construct which I am sure must be able to 
be implemented with c++.  I do not know of any way offhand, but with a little
"syntactical sugar", I am sure someone will come up with a method.  Hopefully
he will not try to patent it though :->

Michael Rutman
Softmed
dpd00609@uxa.cso.uiuc.edu

jans@tekgvs.LABS.TEK.COM (Jan Steinman) (10/14/89)

<Does anyone know of a specific OOL implementation of SENDER?  Any good reasons 
why it should not be included?>

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 <aContext> 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