Есть ли разница между передачей сообщений и вызовом метода, или их можно считать эквивалентными? Вероятно, это характерно для языка; многие языки не поддерживают передачу сообщений (хотя все, что я могу вспомнить о методах поддержки), а те, которые поддерживают, могут иметь совершенно разные реализации. Кроме того, существуют большие различия в вызове методов в зависимости от языка (C против Java против Lisp против вашего любимого языка). Я считаю, что это не зависит от языка. Что вы можете сделать с переданным методом, чего нельзя сделать с вызываемым методом, и наоборот (на вашем любимом языке)?
В чем разница между передачей сообщений и вызовом метода?
Ответы (5)
в первом приближении ответ: нет, пока вы "ведете себя нормально"
Хотя многие думают, что есть - технически это обычно одно и то же: кэшированный поиск фрагмента кода, который должен быть выполнен для конкретной именованной операции (по крайней мере, для нормального случая). Вызов имени операции «сообщение» или «виртуальный метод» не имеет значения.
НО: язык Actor действительно отличается: имея активные объекты (каждый объект имеет неявную очередь сообщений и рабочий поток - по крайней мере, концептуально), параллельная обработка становится проще в обращении (Google также «взаимодействует с последовательными процессами» для большего).
НО: в Smalltalk можно обернуть объекты, чтобы сделать их подобными акторам, без фактического изменения компилятора, синтаксиса или даже перекомпиляции.
НО: в Smalltalk, когда вы пытаетесь отправить сообщение, которое не игнорируется получателем (например, "someObject foo: arg"), создается объект-сообщение, содержащий имя и аргументы, и этот объект-сообщение передается в качестве аргумента сообщения «doesNotUnderstand». Таким образом, объект может сам решить, как поступать с нереализованными отправками сообщений (также известными как вызовы нереализованного метода). Конечно, он может поместить их в очередь, чтобы рабочий процесс упорядочил их ...
Конечно, это невозможно со статически типизированными языками (если только вы не сильно используете отражение), но на самом деле это ОЧЕНЬ полезная функция. Прокси-объекты, загрузка кода по запросу, удаленные вызовы процедур, обучающийся и самомодифицирующийся код, адаптирующиеся и самооптимизирующиеся программы, оболочки corba и dcom, рабочие очереди - все это построено на этой схеме. Его можно использовать неправильно и, конечно же, привести к ошибкам во время выполнения. Так что это двусторонний меч. Резкий и мощный, но опасный в руке новичка ...
РЕДАКТИРОВАТЬ: я пишу здесь о языковых реализациях (как в Java против Smalltalk, а не о межпроцессных механизмах.
IIRC, формально доказано, что они эквивалентны. Не нужно много думать, чтобы хотя бы указать, что они должны быть. Все, что для этого требуется, - это на мгновение игнорировать прямую эквивалентность вызываемого адреса фактическому месту в памяти и рассматривать его просто как число. С этой точки зрения номер - это просто абстрактный идентификатор, который однозначно идентифицирует конкретный тип функциональности, которую вы хотите вызвать.
Даже когда вы вызываете функции на одном компьютере, нет реального требования, чтобы вызываемый адрес напрямую указывал физический (или даже виртуальный) адрес вызываемой функции. Например, хотя почти никто их на самом деле не использует, шлюзы задач защищенного режима Intel позволяют напрямую обращаться к воротам задач. В этом случае только сегментная часть адреса рассматривается как фактический адрес - то есть любой вызов сегмента шлюза задачи заканчивается вызовом того же адреса, независимо от указанного смещения. При желании код обработки может исследовать указанное смещение и использовать его для принятия решения об отдельном вызываемом методе, но взаимосвязь между указанным смещением и адресом вызванной функции может быть совершенно произвольной.
Вызов функции-члена - это просто тип передачи сообщений, который обеспечивает (или, по крайней мере, способствует) оптимизацию в общих обстоятельствах, когда клиент и сервер рассматриваемой службы совместно используют общее адресное пространство. Соответствие 1: 1 между абстрактным идентификатором услуги и адресом, по которому находится провайдер этой услуги, позволяет выполнять тривиальное и исключительно быстрое сопоставление одного с другим.
В то же время не заблуждайтесь по этому поводу: тот факт, что что-то выглядит как вызов функции-члена, не препятствует его фактическому выполнению на другом компьютере или асинхронно, или (часто) и то, и другое. Типичным механизмом для достижения этого является функция прокси, которая переводит «виртуальное сообщение» вызова функции-члена в «реальное сообщение», которое может (например) передаваться по сети по мере необходимости (например, DCOM от Microsoft и CORBA делают это довольно привычно).
Используя Objective-C в качестве примера сообщений и Java для методов, основное отличие состоит в том, что при передаче сообщений объект решает, как он хочет обработать это сообщение (обычно в результате вызывается метод экземпляра в объекте).
Однако в Java вызов метода является более статичным, потому что у вас должна быть ссылка на объект того типа, для которого вы вызываете метод, и в этом типе должен существовать метод с тем же именем и сигнатурой типа, или компилятор буду жаловаться. Что интересно, реальный вызов является динамическим, хотя для программиста это не очевидно.
Например, рассмотрим такой класс, как
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
}
}
Однако в Objective-C компилятор просто выдает предупреждение для передачи сообщения объекту, который, по его мнению, объект может не понимать, но его игнорирование не останавливает выполнение вашей программы.
Несмотря на то, что это очень мощный и гибкий инструмент, при неправильном использовании из-за повреждения стека он может приводить к трудно обнаруживаемым ошибкам.
Взято из статьи, здесь. Также см. эту статью для получения дополнительной информации.
На практике это не одно и то же. Передача сообщений - это способ передачи данных и инструкций между двумя или более параллельными процессами. Вызов метода - это способ вызова подпрограммы. Параллелизм в Erlang основан на прежней концепции с его параллельным ориентированным программированием.
Передача сообщений, скорее всего, включает форму вызова метода, но вызов метода не обязательно включает передачу сообщения. Если бы это было так, то это была бы передача сообщений. Передача сообщений - это одна из форм выполнения синхронизации между параллельными процессами. Вызов метода обычно означает синхронные действия. Вызывающий ожидает завершения метода, прежде чем он сможет продолжить. Передача сообщений - это форма сопрограммы. Вызов метода - это форма подпрограммы.
Все подпрограммы являются сопрограммами, но все сопрограммы не являются подпрограммами.
Есть ли разница между передачей сообщений и вызовом метода, или их можно считать эквивалентными?
Они похожи. Некоторые отличия:
Сообщения могут передаваться синхронно или асинхронно (например, разница между SendMessage и PostMessage в Windows)
Вы можете отправить сообщение, не зная точно, на какой удаленный объект вы его отправляете.
Целевой объект может находиться на удаленном компьютере или в операционной системе.
Object2
выполнить какое-то действие, вы должны передать ему сообщение doSomeAction
. В языках программирования синтаксис сталObject2.SomeAction(...)
; и затем он был вызван 'вызовом метода, а не передачей сообщения. Одним из недостатков почти всех языков является то, чтоObject2.SomeAction(...)
одновременно синхронны и почти всегда ограничиваются одним и тем же потоком или процессом. - person Ian Boyd   schedule 23.04.2021