关于smalltalk中的消息传递有什么特别之处

Agn*_*ngh 8 smalltalk

我正在阅读Smalltalk的介绍.在C++中,类中声明的函数可以由该类的对象调用,类似地,在Smalltalk中,一个关键字(称为message)与对象的名称相邻.(不知道多少,但也想在这里询问是否在回复消息时,是否有执行的独特方法?)

基本上,对于我天真的想法,这似乎只是语法风格的差异.但是,我想知道在内部编译或内存结构方面,这种调用的差异是否具有任何意义.

提前致谢.

PS:我向你们所有人倾诉你的时间和答案.非常感谢.

Ber*_*erg 15

根本区别在于,在Smalltalk中,消息的接收者可以完全控制消息的处理方式.它是一个真正的对象,而不是具有在其上运行的函数的数据结构.

这意味着在Smalltalk中,您可以向任何对象发送任何消息.编译器对此没有任何限制,它们都在运行时处理.在C++中,您只能调用编译器知道的函数.

此外,Smalltalk消息只是符号(唯一字符串),而不是C++中的内存中的函数地址.这意味着可以通过交互方式或通过网络连接轻松发送消息.有一种perform:方法可以让您发送给定字符串名称的消息.

对象甚至接收它未实现的消息.虚拟机检测到该情况并创建一个Message对象,然后发送该messageNotUnderstood:消息.同样,对象是如何处理该未知消息的唯一责任.大多数对象只是继承了引发错误的默认实现,但是对象也可以自己处理它.例如,它可以将这些消息转发到远程对象,或将它们记录到文件等.

  • 不。基本区别在于,消息在 Smalltalk 中是具体化的概念,而在 C++ 中,虚函数调度是隐式的。在 Smalltalk 中,您可以实现一个对象,该对象将接受带有任何类型参数的任何消息(如我的答案的最后一段所述)。在 C++ 中没有办法做到这一点。错误处理只是其中一个应用程序,为远程过程调用编写通用代理是另一个应用程序,为运行时分析检测代码是另一个应用程序,等等。 (3认同)

Uko*_*Uko 12

您在C++中调用函数是因为在编译期间您知道将调用哪个函数(或者至少您在类层次结构中定义了一组有限的函数.

Smalltalk是动态类型和后期绑定的,所以在编译期间你不知道要评估哪个方法(如果有的话).因此,您发送一条消息,如果该对象具有该选择器的方法,则会对其进行评估.否则,引发"消息不理解"异常.

  • 我认为除了实现机制之外还有一个微妙的区别:当你从消息传递的角度思考时,你不会考虑"全局上下文所有权".当你调用一个函数时,该函数现在"拥有世界".发送消息感觉不同; 你不希望接收消息的对象"接管".它类似于程序操纵数据结构之间的差异; 从概念上讲,任何函数都可以操纵任何数据.这种心态影响着设计.我觉得更好. (4认同)

Jay*_*ayK 7

这里已经有了很好的答案.让我添加一些细节(最初,部分内容在评论中).

在普通的C中,每个函数调用的目标是在链接时确定的(除非你使用函数指针).C++添加了虚函数,调用时将调用的实际函数在运行时确定(动态调度,后期绑定).函数指针在某种程度上允许自定义调度机制,但您必须自己编程.

在Smalltalk中,动态调度所有消息发送.在C++术语中,这大致意味着:所有成员函数都是虚拟的,并且没有独立的函数(总有一个接收器).因此,Smalltalk编译器永远不会*决定消息发送将调用哪个方法.相反,调用的方法在运行时由实现Smalltalk的虚拟机确定.

实现虚函数调度的一种方法是虚函数表.Smalltalk中的近似等价物是方法词典.但是,这些字典是可变的,与典型的虚函数表不同,后者由C++编译器生成,并且在运行时不会更改.所有Smalltalk行为(Behavior作为超类Class)都有这样的方法字典.正如@ aka.nice在他的回答中指出的那样,可以查询方法词典.但是,当Smalltalk系统运行时,也可以添加(或删除)方法.当Smalltalk VM调度消息send时,它会搜索接收者超类链的方法字典以获取正确的方法.通常有缓存可以避免查找的重复成本.

另请注意,消息传递是对象在Smalltalk中进行通信的唯一方法.两个对象无法访问彼此的实例变量,即使它们属于同一个类.在C++中,您可以编写打破此封装的代码.因此,消息发送是Smalltalk的基础,而在C++中,它基本上是一个可选功能.

在C++,Java和类似语言中,还有另一种称为函数重载的调度形式.它仅在编译时发生,并根据调用站点上声明的参数类型选择一个函数.你不能在运行时影响它.Smalltalk显然不提供这种形式的调度,因为它没有静态类型的变量.尽管如此,仍然可以使用诸如双重调度之类的习语来实现.其他语言,例如Common Lisp的CLOS或Groovy,提供了更通用的多分派,这意味着将根据接收者的类型和所有参数的运行时类型选择方法.

*一些特殊的消息,例如ifTrue: ifFalse: whileTrue:通常直接编译到条件分支和字节码中的跳转,而不是消息发送.但在大多数情况下,它不会影响语义.


aka*_*ice 6

以下是您在C++中找不到的一些示例

在Smalltalk中,您可以通过发送消息(根据方言取决于超类或命名空间)来创建新类.

在Smalltalk中,您通过向编译器发送消息来编译新方法.

在Smalltalk中,通过发送消息来打开调试器以响应未处理的异常.所有异常处理都是在发送消息方面实现的.

在Smalltalk中,您可以查询类的方法,或通过发送消息来收集其所有实例.

更简单地说,所有控制结构(分支,循环,......)都是通过发送消息来执行的.

它的消息一直在下降.