Smalltalk:邮件的发件人是什么?

Lor*_*ill 5 oop message smalltalk

在smalltalk中,一切都通过向接收器对象发送消息而发生.其语法通常遵循格式接收器消息,其中接收器是发送消息的对象.现在我不能停止想知道,smalltalk消息的发送者是什么?请考虑以下smalltalk语句:

aMorph color: Color yellow
Run Code Online (Sandbox Code Playgroud)

我可以看到aMorph作为消息的接收者,但发送者呢?标准的smalltalk消息语法只有接收者和消息(选择器+参数),我无法识别发送者的位置和位置.或许,消息实际上可以发送自己?

我记得浏览过一篇关于pharo smalltalk反思的文章,其中提到了邮件的发件人,但我无法找到或理解这个"发件人"是什么.任何人都可以向我解释这个吗?谢谢.

bli*_*ihp 6

每当发送消息时,确定并在运行时设置发送方.从目前正在执行的方法的角度来看,它回答了"我们是怎么到达这里的?"的问题.在最常见的情况下,发送方将是发送消息的任何方法,导致当前方法被调用.(一个例外是一个#doesNotUnderstand:处理重定向消息,一些地方比原先预期的目标等)在佳乐例如,如果你大一aMorph color: Color yellow从一个工作区,将发件人UndefinedObject >> DOIT.如果您从MyObject >> myTestSender发送了相同的消息,则发件人将是MyObject >> myTestSender.

现在让我们说你包装aMorph在一个代理对象 myProxy,MyProxyObject的一个实例,它的doesNotUnderstand:方法将它收到的所有内容转发给底层aMorph对象.在这种情况下,当你这样做时myProxy color: Color yellow,发件人将是MyProxyObject >> doesNotUnderstand : . (除非你的doesNotUnderstand:方法进一步操作运行时...如果需要它可以做什么)这实际上是一个很好的例子,你可能需要查看发送者#color:是谁:它被调用但你不明白因为代理增加了一个对您来说可能不明显的间接级别.

因此,为了查看发件人是谁,您可以在color:方法中添加以下内容:

Transcript show: thisContext sender asString.
Run Code Online (Sandbox Code Playgroud)

从代码的角度来看,处理发送方是隐式的,并且在正常的代码执行期间由Smalltalk运行时为您处理.除非您要对某些代码进行故障排除或者需要在运行时进行内省或更改,否则您不会经常查看发件人.

现在,这可能会引发一个问题:"到底是thisContext什么?" 它是一个特殊的变量,代表了callstack的顶部,是许多人最初难以绕过头脑的东西.有关详细信息,请参阅Smalltalk如何操作调用堆栈帧.

附录(希望这将清除Leandro的答案和我的答案之间的任何混淆)

Leandro的答案是将发送者视为一个通用术语,并考虑更大的历史背景,而我的是一个更现代的Squeak/Pharo中心,并具有非常具体的含义.我同意Leandro的观点,即发件人这个术语含糊不清,并且在实施过程中没有标准化(正如我们的不同答案所证明的那样).只是为了进一步混淆水域,在蓝皮书中发件人的引用正在谈论发送上下文......这是也不selfthisContext sender.但是,关于该问题的评论中提到的链接在其含义(即thisContext sender)中是明确的,这在提及Squeak/Pharo代码时通常是指的.那么哪个答案是正确的取决于您是否正在查看特定的Smalltalk实现(在这种情况下,正确的用法是您正在使用的实现所决定的)或者在讨论没有特定的Smalltalk实现时作为更通用的术语(在这种情况下,Leandro是正确的:它的解释是因为它的使用已经超载到接近无意义的情况)


Lea*_*lia 5

您可以将发件人视为self。换句话说,当一个方法被激活时(即在其执行期间), 所代表的对象self可以被解释为该方法主体中发送的所有消息的发送者。

例如,考虑方法#paint:,定义OurClass

paint: aMorph
  aMorph color: Color yellow
Run Code Online (Sandbox Code Playgroud)

一旦执行该方法,OurClass接收paint:消息的(子)实例将变为self。那么,在该方法的激活过程中,self可以将发送者的角色归因color:aMorph

但请注意,这只是一个解释问题。例如,您还可以考虑正在执行的进程并将发送者标识为激活的进程框架#color:

虽然两种解释都是有效的,但事实是,在 Smalltalk 中,发送者的概念是无关紧要的,因为发送消息的行为是原始的,即在虚拟机中实现,而不是在虚拟映像中实现。

当然,出于沟通目的,将该角色分配给某人甚至谈论发件人是有用的。但隐含的对象取决于上下文。例如,在调试时,您可以通过调用帧来识别发送者。然而,由于消息发送“神奇地”发生,因此实际上不需要将发送者的角色附加到任何对象。

即使在 Bee Smalltalk 中,由于没有 VM,您可以访问运行时的内部,发送者的概念也是繁琐且不必要的。从技术上讲,Bee 中的每个发送都有一个SendSite对象,该对象执行发送消息所需的所有步骤(PIC、查找等),并且由于您可以检查这些对象并向它们发送消息,因此您可以推测在 Bee 中发送者是这SendSite。但同样,这需要解释。事实上里面没有senderivarSendSiteivar ,只是因为 Smalltalk 语义不需要这样的东西。

附录

当我说 的概念sender需要解释时,我的意思是在发送机制的任何实现中都没有使用这样的概念。更准确地说,执行发送的(原始)代码由执行方法查找的缓存例程组成,该例程仅考虑receiverbehaviorselector而忽略“发送者”。

另请注意,消息发送从“调用者”获取的主要“数据”是参数。如果我们更深入地研究所有这些的机器代码实现,我们可以说另一个是返回地址,用于链接帧。这就是为什么我提到调用者进程框架的“发送者”概念,这对于调试器实现中的具体化是有意义的。

我的观点是,在 Smalltalk 中,没有明确的定义,这就是为什么与、、和等sender相关概念相比很难识别它。receiverselectorargumentsbehaviormethod send

确实,您可以使用伪变量thisContext来获取sender当前激活的 。如果这样做,您将获得在调用框架中模拟的对象self,这是sender. 即使通过引用该对象,您可以利用它来提供更多功能,但该对象和消息发送机制sender中仍然不存在该功能。Message