В чем разница между передачей сообщений и вызовом метода?

Есть ли разница между передачей сообщений и вызовом метода, или их можно считать эквивалентными? Вероятно, это характерно для языка; многие языки не поддерживают передачу сообщений (хотя все, что я могу вспомнить о методах поддержки), а те, которые поддерживают, могут иметь совершенно разные реализации. Кроме того, существуют большие различия в вызове методов в зависимости от языка (C против Java против Lisp против вашего любимого языка). Я считаю, что это не зависит от языка. Что вы можете сделать с переданным методом, чего нельзя сделать с вызываемым методом, и наоборот (на вашем любимом языке)?


person Scrollbar    schedule 25.08.2010    source источник
comment
Вы имеете в виду, что вы можете сделать с переданным- сообщением, которое вы не можете сделать ...? Если так, я внесу поправку.   -  person Bevan    schedule 25.08.2010
comment
Первоначальная концепция объектно-ориентированного программирования заключалась в передаче сообщений между объектами. Если вы хотите Object2 выполнить какое-то действие, вы должны передать ему сообщение do SomeAction. В языках программирования синтаксис стал Object2.SomeAction(...); и затем он был вызван 'вызовом метода, а не передачей сообщения. Одним из недостатков почти всех языков является то, что Object2.SomeAction(...) одновременно синхронны и почти всегда ограничиваются одним и тем же потоком или процессом.   -  person Ian Boyd    schedule 23.04.2021


Ответы (5)


в первом приближении ответ: нет, пока вы "ведете себя нормально"

Хотя многие думают, что есть - технически это обычно одно и то же: кэшированный поиск фрагмента кода, который должен быть выполнен для конкретной именованной операции (по крайней мере, для нормального случая). Вызов имени операции «сообщение» или «виртуальный метод» не имеет значения.

НО: язык Actor действительно отличается: имея активные объекты (каждый объект имеет неявную очередь сообщений и рабочий поток - по крайней мере, концептуально), параллельная обработка становится проще в обращении (Google также «взаимодействует с последовательными процессами» для большего).

НО: в Smalltalk можно обернуть объекты, чтобы сделать их подобными акторам, без фактического изменения компилятора, синтаксиса или даже перекомпиляции.

НО: в Smalltalk, когда вы пытаетесь отправить сообщение, которое не игнорируется получателем (например, "someObject foo: arg"), создается объект-сообщение, содержащий имя и аргументы, и этот объект-сообщение передается в качестве аргумента сообщения «doesNotUnderstand». Таким образом, объект может сам решить, как поступать с нереализованными отправками сообщений (также известными как вызовы нереализованного метода). Конечно, он может поместить их в очередь, чтобы рабочий процесс упорядочил их ...

Конечно, это невозможно со статически типизированными языками (если только вы не сильно используете отражение), но на самом деле это ОЧЕНЬ полезная функция. Прокси-объекты, загрузка кода по запросу, удаленные вызовы процедур, обучающийся и самомодифицирующийся код, адаптирующиеся и самооптимизирующиеся программы, оболочки corba и dcom, рабочие очереди - все это построено на этой схеме. Его можно использовать неправильно и, конечно же, привести к ошибкам во время выполнения. Так что это двусторонний меч. Резкий и мощный, но опасный в руке новичка ...

РЕДАКТИРОВАТЬ: я пишу здесь о языковых реализациях (как в Java против Smalltalk, а не о межпроцессных механизмах.

person blabla999    schedule 25.08.2010

IIRC, формально доказано, что они эквивалентны. Не нужно много думать, чтобы хотя бы указать, что они должны быть. Все, что для этого требуется, - это на мгновение игнорировать прямую эквивалентность вызываемого адреса фактическому месту в памяти и рассматривать его просто как число. С этой точки зрения номер - это просто абстрактный идентификатор, который однозначно идентифицирует конкретный тип функциональности, которую вы хотите вызвать.

Даже когда вы вызываете функции на одном компьютере, нет реального требования, чтобы вызываемый адрес напрямую указывал физический (или даже виртуальный) адрес вызываемой функции. Например, хотя почти никто их на самом деле не использует, шлюзы задач защищенного режима Intel позволяют напрямую обращаться к воротам задач. В этом случае только сегментная часть адреса рассматривается как фактический адрес - то есть любой вызов сегмента шлюза задачи заканчивается вызовом того же адреса, независимо от указанного смещения. При желании код обработки может исследовать указанное смещение и использовать его для принятия решения об отдельном вызываемом методе, но взаимосвязь между указанным смещением и адресом вызванной функции может быть совершенно произвольной.

Вызов функции-члена - это просто тип передачи сообщений, который обеспечивает (или, по крайней мере, способствует) оптимизацию в общих обстоятельствах, когда клиент и сервер рассматриваемой службы совместно используют общее адресное пространство. Соответствие 1: 1 между абстрактным идентификатором услуги и адресом, по которому находится провайдер этой услуги, позволяет выполнять тривиальное и исключительно быстрое сопоставление одного с другим.

В то же время не заблуждайтесь по этому поводу: тот факт, что что-то выглядит как вызов функции-члена, не препятствует его фактическому выполнению на другом компьютере или асинхронно, или (часто) и то, и другое. Типичным механизмом для достижения этого является функция прокси, которая переводит «виртуальное сообщение» вызова функции-члена в «реальное сообщение», которое может (например) передаваться по сети по мере необходимости (например, DCOM от Microsoft и CORBA делают это довольно привычно).

person Jerry Coffin    schedule 25.08.2010

Используя 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 компилятор просто выдает предупреждение для передачи сообщения объекту, который, по его мнению, объект может не понимать, но его игнорирование не останавливает выполнение вашей программы.

Несмотря на то, что это очень мощный и гибкий инструмент, при неправильном использовании из-за повреждения стека он может приводить к трудно обнаруживаемым ошибкам.

Взято из статьи, здесь. Также см. эту статью для получения дополнительной информации.

person Jeshurun    schedule 21.08.2012

На практике это не одно и то же. Передача сообщений - это способ передачи данных и инструкций между двумя или более параллельными процессами. Вызов метода - это способ вызова подпрограммы. Параллелизм в Erlang основан на прежней концепции с его параллельным ориентированным программированием.

Передача сообщений, скорее всего, включает форму вызова метода, но вызов метода не обязательно включает передачу сообщения. Если бы это было так, то это была бы передача сообщений. Передача сообщений - это одна из форм выполнения синхронизации между параллельными процессами. Вызов метода обычно означает синхронные действия. Вызывающий ожидает завершения метода, прежде чем он сможет продолжить. Передача сообщений - это форма сопрограммы. Вызов метода - это форма подпрограммы.

Все подпрограммы являются сопрограммами, но все сопрограммы не являются подпрограммами.

person chubbsondubs    schedule 25.08.2010
comment
Передача сообщений также может относиться к способу вызова методов в таких языках, как Smalltalk, Objective-C и Ruby. - person mipadi; 25.08.2010
comment
Да, эти языки любят думать об этом как о передаче сообщений, но это подпрограмма, которая включает в себя добавление чего-либо в стек при приостановке метода, вызывающего подпрограмму. Реализация представляет собой вызов метода, передаваемого из стека, что подразумевает, что вызывающий объект заблокирован, пока он ожидает возврата вызывающей процедуры. Передача сообщений не имеет такой семантики. Моя точка зрения заключалась в том, что ему не нужно ждать завершения процедуры, которую он вызывает. Вот в чем разница. - person chubbsondubs; 12.03.2013
comment
IMO OP на самом деле не обсуждает межпроцессное взаимодействие. - person Dave Newton; 11.04.2016
comment
И я тоже. Я не говорил конкретно о IPC. Я использовал процесс в общем смысле, имея в виду любую задачу, выполняемую в процессе ОС. Но внутри процесса вам все равно нужно передавать информацию между параллельными задачами. Так уж получилось, что оба эти метода также можно использовать для IPC, но это не совсем IPC. - person chubbsondubs; 11.04.2016

Есть ли разница между передачей сообщений и вызовом метода, или их можно считать эквивалентными?

Они похожи. Некоторые отличия:

Сообщения могут передаваться синхронно или асинхронно (например, разница между SendMessage и PostMessage в Windows)

Вы можете отправить сообщение, не зная точно, на какой удаленный объект вы его отправляете.

Целевой объект может находиться на удаленном компьютере или в операционной системе.

person ChrisW    schedule 25.08.2010
comment
Приносим извинения за то, что давно нашли ответ, но в отношении целевого объекта может быть удаленный компьютер или O / S - действительно ли это уникально для передачи сообщений или вызова метода? Если я правильно понял ваше значение, вы утверждаете это как свойство передачи сообщений. Если да, то не противоречит ли этому вызов удаленного метода в Java? - person obfuscation; 02.08.2011