Scr*_*bar 31 language-agnostic message-passing method-invocation
消息传递和方法调用之间是否存在差异,或者它们是否可以被视为等效?这可能是语言特有的; 许多语言不支持消息传递(尽管我能想到支持方法的所有语言),并且那些语言可以具有完全不同的实现.此外,方法调用存在很大差异,具体取决于语言(C vs. Java vs Lisp vs您最喜欢的语言).我相信这与语言无关.对于使用调用方法无法执行的传递方法,您可以做什么,反之亦然(使用您喜欢的语言)?
作为第一个近似,答案是:无,只要你"行为正常"
尽管许多人认为 - 从技术上讲,它通常是相同的:对特定命名操作执行的一段代码的缓存查找(至少对于正常情况).将操作名称称为"消息"或"虚拟方法"并没有什么区别.
但是:Actor语言实际上是不同的:在拥有活动对象(每个对象都有一个隐含的消息队列和一个工作者线程 - 至少在概念上),并行处理becones更容易处理(谷歌也"沟通顺序进程"更多).
但是:在Smalltalk中,可以包装对象以使它们像actor一样,而无需实际更改编译器,语法甚至重新编译.
但是:在Smalltalk中,当您尝试发送一个接收者不在其中的消息(即"someObject foo:arg")时,会创建一个包含名称和参数的消息对象,并传递该消息对象作为"doesNotUnderstand"消息的参数.因此,对象可以自己决定如何处理未实现的消息发送(也称为未实现方法的调用).它当然可以 - 将它们推入队列中,以便工作进程对它们进行顺序化......
当然,对于静态类型语言来说这是不可能的(除非你非常大量地使用反射),但实际上它是一个非常有用的功能.代理对象,按需加载代码,远程过程调用,学习和自修改代码,调整和自我优化程序,corba和dcom包装器,工作队列都是基于该方案构建的.它可能被误用,并导致运行时错误 - 当然.所以这是一把双刃剑.锋利而强大,但在初学者手中却很危险......
编辑:我在这里写关于语言实现(如Java与Smalltalk一样 - 不是进程间机制.
IIRC,他们已经被正式证明是等同的.至少表明他们应该这样做并不需要花费太多的思考.关于所需要的只是暂时忽略被调用地址与内存中实际点的直接等价,并将其简单地视为一个数字.从这个角度来看,该数字只是一个抽象标识符,它唯一地标识您想要调用的特定类型的功能.
即使您在同一台机器中调用函数,也没有真正要求被调用地址直接指定被调用函数的物理(甚至虚拟)地址.例如,虽然几乎没有人真正使用它们,但英特尔保护模式任务门允许直接调用任务门本身.在这种情况下,只有地址的段部分被视为实际地址 - 即,对任务门段的任何调用最终都会调用相同的地址,而不管指定的偏移量如何.如果需要,处理代码可以检查指定的偏移量,并使用它来决定要调用的单个方法 - 但是指定的偏移量与被调用函数的地址之间的关系可以完全是任意的.
成员函数调用仅仅是一种消息传递,其在所讨论的服务的客户端和服务器共享公共地址空间的共同情况下提供(或至少促进)优化.抽象服务标识符与该服务的提供者所驻留的地址之间的1:1对应关系允许从一个到另一个的平凡,异常快速的映射.
同时,不要搞错:事情看起来像成员函数调用并不会阻止它实际在另一台机器上执行或异步,或(经常)两者都执行.实现此目的的典型机制是代理功能,它将成员函数调用的"虚拟消息"转换为"真实消息",可以(例如)根据需要通过网络传输(例如,Microsoft的DCOM和CORBA都这样做)这很常规).
使用Objective-C作为消息和Java方法的示例,主要区别在于,当您传递消息时,Object决定它如何处理该消息(通常导致调用Object中的实例方法).
但是在Java中,方法调用是一个更静态的东西,因为您必须具有对要调用方法的类型的Object的引用,并且该类型或编译器中必须存在具有相同名称和类型签名的方法会抱怨 有趣的是实际调用是动态的,尽管这对程序员来说并不明显.
例如,考虑一个类,如
class MyClass {
void doSomething() {}
}
class AnotherClass {
void someMethod() {
Object object = new Object();
object.doSomething(); // compiler checks and complains that Object contains no such method.
// However, through an explicit cast, you can calm the compiler down,
// even though your program will crash at runtime
((MyClass) object).doSomething(); // syntactically valid, yet incorrect
}
}
Run Code Online (Sandbox Code Playgroud)
但是,在Objective-C中,编译器只是向您发出警告,将消息传递给它认为对象可能无法理解的对象,但忽略它并不会阻止程序执行.
虽然这非常强大且灵活,但由于堆栈损坏而导致错误使用时,可能会导致难以发现的错误.
实际上,它们实际上不是同一回事。消息传递是在两个或多个并行进程之间传输数据和指令的方式。方法调用是一种调用子例程的方法。Erlang的并发是基于前一概念及其并发面向程序设计的。
消息传递很可能涉及一种方法调用形式,但是方法调用不一定涉及消息传递。如果做到了,那就是消息传递。消息传递是在并行进程之间执行同步的一种形式。方法调用通常表示同步活动。调用者等待该方法完成才能继续。消息传递是协程的一种形式。方法调用是子例程的一种形式。
所有子例程都是协程,但不是所有协程。
消息传递和方法调用之间有区别吗?或者它们可以被认为是等效的吗?
他们很相似。一些差异:
消息可以同步传递,也可以异步传递(例如Windows中SendMessage和PostMessage的区别)
您可能会在不确切知道要将消息发送到哪个远程对象的情况下发送消息
目标对象可能位于远程计算机或操作系统上。
| 归档时间: |
|
| 查看次数: |
9124 次 |
| 最近记录: |