Различия между сообщениями и методами?

13

В Objective C у вас есть концепция отправки сообщений другим объектам, и это очень похоже на вызов методов в таких языках, как C # и Java.

Но какие именно тонкие различия? Как я должен думать об обмене сообщениями, думая о моем коде?

Примечание: здесь я немного разбираюсь, я разработчик на C # / Java и пытаюсь понять некоторые концепции Objective C.

Видар
источник
2
Поскольку все они разные языки, различия не являются тонкими. Это разные языки. "когда думаешь о моем коде"? Какой код? Когда вы думаете о Java или C #, вы не думаете о сообщениях. Вы думаете о методах. Можете ли вы уточнить, как несвязанные языки с несвязанными понятиями могут иметь "тонкие" различия?
S.Lott
1
Пожалуйста, задайте свой вопрос на stackoverflow.com
Амир Резаи
1
Этот вопрос действительно должен быть на StackOverflow? Это вопрос о концепции программирования, а не о каком-то коде, который у меня есть. Может быть, я не прав, я не знаю - границы стираются ...
Видар
1
@ Видар, вопрос не субъективный. Вы ищете определение учебника. Программисты больше для мнений, опыта и субъективных вопросов.
Стивен Фурлани
1
ОК - есть ли способ заставить модератора переместить этот вопрос в StackOverflow?
Видар

Ответы:

10

Сообщение - это имя селектора и параметры этого селектора.

Селектор это символ.

Метод - это фрагмент кода в классе, идентифицируемый селектором.

Другими словами, [foo bar: baz]говорится «отправить сообщение, вызванное @selector(bar:)с параметром, bazк объекту foo. Вы можете отправить это сообщение множеству различных объектов.

Напротив, метод bar: для Fooможет выглядеть

-(int)bar:(int)n {
  return n + 1;
}

но FooTwoможет выглядеть

-(int)bar:(int)n {
  return n + 2;
}

(Я надеюсь, что у меня есть правильный синтаксис; прошло много времени с тех пор, как я последний раз касался Objective-C.)

Когда вы отправляете сообщение, ядро ​​Objective C отправляет сообщение, fooкоторое решает, понимает ли оно сообщение. Он решает это на основе того, может ли он найти метод, идентифицированный этим селектором.

Два метода с одинаковым именем и одно сообщение.

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

Фрэнк Шиарар
источник
итак ... сообщение - это когда вы вызываете dispinterface (селектор a.invoke, args), а метод - когда вы вызываете интерфейс (a.methodName)? Разве это не делает Java, JavaScript, все динамические языки имеют сообщения, потому что все происходит через двойной интерфейс, а не через прямые переходы и смещение в переходы vtable)?
Дмитрий
3

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

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

Как следует из конца предыдущего абзаца, с действительно практической точки зрения, между этими двумя понятиями очень мало различий. Это просто два (очень немного) разных способа поддержки позднего связывания. Хотя поиск на основе сообщений, как правило, немного медленнее, было бы довольно необычно, если бы разница была действительно значительной. Для большинства практических целей это всего лишь два разных способа достижения одной и той же цели.

Джерри Гроб
источник
2
У вас есть ссылки, показывающие доказательства? Я хотел бы взглянуть. Существует огромная разница между вызовом метода Java и отправкой сообщений Smalltalk не только из-за поздней привязки, но и из-за развязки отправителя и получателя: вы не можете определить, обрабатывает ли получатель сообщения его или пересылает сообщение на, например.
Фрэнк Шиарар
1

В Objective-C сообщения имеют позднюю привязку. То есть они разрешаются во время выполнения. C # поддерживает аналогичную конструкцию через ключевое слово Dynamic, которое также объявляет объект с поздним связыванием.

Майкл Браун
источник
0

Обычно вызовы методов разрешаются во время компиляции (если вы не используете отражение в Java), тогда как сообщения в Objective C отправляются во время выполнения.

Хайко Рупп
источник
2
Если вызовы методов разрешены во время компиляции, вы не используете ООП, вы используете синтаксический сахар для перегруженных функций, принимающих в structкачестве первого параметра. Позднее связывание является неотъемлемой частью полиморфизма и, следовательно, ООП.
2
Да. Но все же вы можете кодировать вызов метода только для чего-то (в Java), что хорошо известно во время компиляции. Вызов MyObject.foo () выдаст ошибку, если в MyObject или MyInterface не определен метод foo (). ObjC позволит отправить вам сообщение «foo» для объекта MyObject - и если MyObject не имеет «foo», это будет бомбить во время выполнения.
Хайко Рупп,
Я думал, что Objective C был скомпилированным языком?
Видар
1
Это нереально для раннего / позднего связывания (динамическая типизация или структурная типизация - в вашем примере вызовы методов проверяются во время компиляции, но не обязательно отправляются ). @ Видар: Да, но это добавляет волшебства для динамических функций. Вы также можете скомпилировать Python.
@Vidar: Это не проблема скомпилированного или интерпретированного, а скорее статического и динамического. В статических языках ООП, таких как Java, компилятор проверяет, что класс определяет метод на этапе компиляции. В языке с динамической типизацией, таком как Objective-C, сообщения передаются во время выполнения.
Mipadi
-1

Сообщения обрабатываются либо ядром, либо самим языком (например, для ObjC существует очень маленький ассемблерный код).

Например, в ядре Linux сообщения обрабатываются с помощью системных вызовов / функций: вы можете узнать о них, если будете искать в системном программировании Unix.

Основное различие между вызовом метода и сообщением заключается в следующем:

  • вызов метода происходит только в вашем коде: в ASM он переводится PUSH переданных аргументов.

  • сообщение ядра - это в основном то, что отправляется в ядро, которое отслеживается и отправляется обратно определенным процессам. Я могу ошибочно принять их за каналы, но что угодно: знайте, что уже существует механизм, который позволяет вам запускать несколько программ одновременно и позволять общаться одновременно. Конечно, не надейтесь, что это будет работать так же на Windows или других ОС.

jokoon
источник
Это не «передача сообщений», поскольку это относится к языкам программирования.
Mipadi