Smalltalk: What is the sender of a message?
Asked Answered
B

5

9

In smalltalk, everything happens by sending messages to receiver objects. Its syntax usually follows the format receiver message, in which receiver is an object that the message is sent to. Now I cant stop wondering, what is the sender of smalltalk messages? Consider the following smalltalk statement:

aMorph color: Color yellow

I can see aMorph as the receiver of message, but what about the sender? The standard smalltalk message syntax has only receiver and the message(selecter + arguments), I cannot identify what and where the sender is. Or perhaps, a message can actually send itself?

I remember browsing through an article about reflection in pharo smalltalk in which it mentioned sender of a message, but I cant find or understand what is this 'sender'. Can anyone explain this to me about this? Thanks.

Bonkers answered 18/10, 2018 at 0:14 Comment(2)
According to this answer Pharo understands the word sender. Do you remember seeing another word? Or are you asking how to retrieve the sender of a message?Beerbohm
I found it from this article: pharo.gforge.inria.fr/PBE1/PBE1ch15.html And after reading it through, I still cant understand what the sender is. A previous article on the same website explains message syntax(chapter 4), which mentions no such thing as sender of message.Bonkers
B
7

The sender is determined and set at runtime whenever a message is sent. From the perspective of the currently executing method, it answers the question 'how did we get here?' In the most common case, the sender would be whatever method sent the message that resulted in the current method being called. (one exception would be a #doesNotUnderstand: handler that redirects a message to some place other than the originally intended destination) In Squeak for example, if you doIt on aMorph color: Color yellow from a workspace, the sender will be UndefinedObject>>DoIt. If you sent the same message from MyObject>>myTestSender, the sender will be MyObject>>myTestSender.

Now let's say you wrapped aMorph in a proxy object myProxy, an instance of MyProxyObject, and its doesNotUnderstand: method forwards everything it receives to the underlying aMorph object. In this case, when you doIt myProxy color: Color yellow, the sender will be MyProxyObject>>doesNotUnderstand:. (unless your doesNotUnderstand: method further manipulates the runtime... which it can do if it needs to) This is actually a good example of when you might need to look at who the sender of #color: is: it's being invoked but you don't understand from where since the proxy adds a level of indirection that may not be obvious to you.

So in order to see who the sender is, you could add the following to the color: method:

Transcript show: thisContext sender asString.

From the perspective of your code, dealing with sender is implicit and handled for you by the Smalltalk runtime during normal code execution. Unless you're troubleshooting some code or otherwise needing to introspect or alter things at runtime, you won't often be looking at the sender.

Now this may raise the question 'what the heck is thisContext?' It's a special variable representing the top of the callstack and is something that many people have a difficult time wrapping their heads around initially. See How does Smalltalk manipulate call stack frames for more information.

Addendum (hopefully this will clear up any confusion between Leandro's answer and mine)

Leandro's answer is looking at sender as a general term and considers the larger historical context, while mine is a more contemporary Squeak/Pharo-centric one and has a very specific meaning. I agree with Leandro's point that the term sender is ambiguous and not standardized across implementations (as our different answers prove.) Just to muddy the waters even further, in the Blue Book references to sender are talking about the sending context... which is neither self nor thisContext sender. However, the links referred to in the comments on the question were explicit in their meaning (i.e. thisContext sender) as is commonly meant when referring to Squeak/Pharo code. So which answer is correct depends on whether you are looking at a specific Smalltalk implementation (in which case, the correct usage is whatever one the implementation you are using has decided on) or as a more general term when talking about no particular Smalltalk implementation (in which case Leandro is correct: it's subject to interpretation as its usage has been overloaded to near-meaninglessness)

Bysshe answered 18/10, 2018 at 2:15 Comment(0)
T
5

You can think of the sender as being self. In other words, when a method is activated (i.e., during its execution), the object represented by self can be interpreted as the sender of all the messages sent in the method's body.

Consider for instance the method #paint:, defined in OurClass as

paint: aMorph
  aMorph color: Color yellow

As soon as this method is executed, the (sub)instance of OurClass receiving the paint: message, will become self. Well, during this activation of the method, self could be attributed the role of the sender of color: to aMorph.

Note however, that this is just a matter of interpretation. For instance, you could also consider the process being executed and identify the sender as the process frame that activated #color:.

While both interpretations are valid, the reality is that in Smalltalk the notion of sender is irrelevant because the act of sending a message is primitive, i.e., implemented in the Virtual Machine, not in the Virtual Image.

Of course, for communication purposes it is useful to assign that role to someone and even speak about the sender. But the object implied depends on the context. For instance, when debugging, you would identify the sender with the calling frame. However, since message sends happen "magically", there is no actual need to attach the role of sender to any object.

Even in Bee Smalltalk, where you can reach the internals of the runtime because there is no VM, the notion of sender is also fussy and rather unnecessary. Technically speaking, every send in Bee has a SendSite object that performs all the steps needed to send the message (PIC, lookup, etc.) And since you can inspect these objects and send messages to them, you could speculate that in Bee the sender is the SendSite. But again, this is subject to interpretation. In fact there is no sender ivar in the SendSite class simply because the Smalltalk semantics doesn't need such a thing.

Addendum

When I say that the notion of sender is subject to interpretation what I mean is that such a notion is not used in any implementation of the send mechanism. More precisely, the (primitive) code that performs the send consists of a cached routine that performs the method lookup, which only takes into account the receiver's behavior and the selector, disregarding the "sender".

Note also that the main piece of "data" that the message send gets from the "caller" are the arguments. And if we dig deeper in the machine code realization of all of this, we could argue that the other one is the return address, which is used to link the frames. This is why I mentioned the notion of "sender" as referred to the caller process frame, which is meaningful for its reification in the implementation of the debugger.

My point is that in Smalltalk there is no clear definition of sender and that's why it is so hard to identify it when compared to relevant notions such as receiver, selector, arguments, behavior and method send.

It is true that you can use the pseudo variable thisContext to get the sender of the current activation. If you do this, you will get the object that impersonated self in the calling frame, which is the other interpretation of sender. And even though by having a reference to that object you could make use of it to provide more features, the sender will remain absent from the Message object and the message send machinery.

Timepleaser answered 18/10, 2018 at 2:59 Comment(4)
I could squint my eyes and say 'ok, I can kind of see where he's going' until I got to the last three paragraphs which are wrong as a general statement. While the actual mechanism to send a message is implemented in the VM, it is absolutely exposed in the image in all Smalltalks I'm familiar with. The sender can be both introspected (i.e. thisContext sender) and manipulated (i.e. MethodContext sender:receiver:method:arguments: in Squeak dialects at least). In fairness, I'm not familiar with Bee which may work exactly like you say, but your assertion conflicts with 'most' Smalltalks.Bysshe
@Bysshe Thanks for your feedback. I've expanded my answer in an attempt to address your reaction, which to me is valid and interesting.Timepleaser
OK, I think I see the problem: we're answering two different questions. Not enough space in comments to address... I'll update my answer elaborating.Bysshe
@Bysshe Thanks for the clarifications. Good answer!Timepleaser
R
3

If you are interested in how Smalltalk works look at @blihp's and @leandro-caniglia's answers. Also Deep Into Pharo (14.5 Contexts: representing method execution) has information on Context (named MethodContext until Pharo 3).

If you want to experiment with it, at least in Pharo, the pseudo-variable thisContext gives access to the current execution point. You can put:

thisContext copy inspect.

in your method to see what information you can get about a specific execution point. This information includes the sender.

But if you were wondering if you should, on a regular basis, access the sender of a message in your methods, the answer is no. If you need to know the object sending a message in a regular method, pass the sender (self) along as an additional parameter.

Retrograde answered 18/10, 2018 at 8:33 Comment(2)
Your last paragraph is, so far, the most useful piece of advice in this discussion!Timepleaser
@LeandroCaniglia Sorry for misspelling your name :)Retrograde
C
0

You have identified aMorph as the receiver of a message. Now, what does aMorph do? It sends messages to various things. When aMorph is responding to the message it reveived, It is the sender. It was the receiver, it becomes the sender. When aMorph is done, it stops being sender, and gives an answer to whatever sent it the message it was working on.

Of course everytime aMorph sends a message, the receiver gets to be the sender while it works out an answer.

And so on.

Cryptography answered 31/10, 2018 at 0:43 Comment(0)
S
0

Below in the message anObject bar is explicit that whoever sent the message was SomeClass instance. But within the method that responds to the message you must resort to the services of thisContext.

SomeClass>>foo
    | anObject |
    anObject := AnotherClass new.
    anObject bar

AnotherClass>>bar
    | context senderObject receiver |
    context := thisContext.
    senderObject := context sender receiver.
    receiver := self
Shuttlecock answered 17/6, 2020 at 22:18 Comment(2)
So the context object is the sender, while receiver is the object that will get the message and respond with activation of its method(s)? Is this the right way to interpret it?Bonkers
@LordYggdrasill, I corrected my answer because there was a mistake. I don't know if the correction made clarifies your question.Shuttlecock

© 2022 - 2024 — McMap. All rights reserved.