Smalltalk: кто является отправителем сообщения? - PullRequest
0 голосов
/ 18 октября 2018

В smalltalk все происходит путем отправки сообщений получателям.Его синтаксис обычно соответствует формату сообщение получателя , в котором получатель является объектом, в который отправляется сообщение.Теперь я не могу перестать задаваться вопросом, кто является отправителем сообщений Smalltalk?Рассмотрим следующий оператор smalltalk:

aMorph color: Color yellow

Я могу видеть aMorph как получателя сообщения, но как насчет отправителя?Стандартный синтаксис сообщения smalltalk имеет только получателя и сообщение (selecter + arguments), я не могу определить, что и где находится отправитель.Или, может быть, сообщение действительно может отправить сам?

Я помню, как просматривал статью об отражении в pharo smalltalk, в которой упоминался отправитель сообщения, но я не могу найти или понять, что это за «отправитель».Может кто-нибудь объяснить мне об этом?Благодарю.

Ответы [ 4 ]

0 голосов
/ 31 октября 2018

Вы указали aMorph как получателя сообщения.Теперь, что делает aMorph?Он отправляет сообщения на разные вещи.Когда aMorph отвечает на сообщение, которое он получил, это отправитель.Это был получатель, он становится отправителем.Когда aMorph завершается, он перестает быть отправителем и дает ответ любому отправившему ему сообщение, над которым он работал.

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

И т. д.

0 голосов
/ 18 октября 2018

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

Рассмотрим, например,метод #paint:, определенный в OurClass как

paint: aMorph
  aMorph color: Color yellow

Как только этот метод будет выполнен, (суб) экземпляр OurClass, получающий сообщение paint:, станет self.Ну, во время этой активации метода self можно было бы отнести роль отправителя color: к aMorph.

Обратите внимание, что это всего лишь вопрос интерпретации.Например, вы также можете рассмотреть выполняемый процесс и определить отправителя как фрейм процесса, который активировал #color:.

Хотя обе интерпретации верны, реальность такова, что в Smalltalk понятие отправителя не имеет значения, посколькупроцесс отправки сообщения является примитивным, т. е. реализуется в виртуальной машине, а не в виртуальном образе.

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

Даже в Bee Smalltalk, где вы можете получить доступ к внутренним компонентам среды выполнения, потому что нет виртуальной машины, понятие отправителя также является суетливым и довольно ненужным.Технически говоря, каждая отправка в Bee имеет объект SendSite, который выполняет все шаги, необходимые для отправки сообщения (PIC, поиск и т. Д.). И поскольку вы можете проверять эти объекты и отправлять им сообщения, вы можете предположить, что в Beeотправитель SendSite.Но опять же, это подлежит интерпретации.На самом деле sender ivar в классе SendSite нет просто потому, что семантике Smalltalk в этом нет необходимости.

Addendum

Когда я говорю, что понятие sender подлежит интерпретации, что я имею в виду, что такое понятие не используется ни в одной реализации механизма отправки.Точнее, (примитивный) код, который выполняет отправку, состоит из кэшированной подпрограммы, которая выполняет поиск метода, который учитывает только receiver behavior и selector, не учитывая «отправителя».

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

Я хочу сказать, что в Smalltalk нет четкого определенияsender, и поэтому его так трудно идентифицировать по сравнению с соответствующими понятиями, такими как receiver, selector, arguments, behavior и method send.

Это правда, чтоВы можете использовать псевдопеременную thisContext, чтобы получить sender текущей активации.Если вы сделаете это, вы получите объект, который олицетворял self в кадре вызова, что является другой интерпретацией sender.И хотя, имея ссылку на этот объект, вы можете использовать его для предоставления дополнительных функций, sender будет отсутствовать в объекте Message и в механизме отправки сообщений.

0 голосов
/ 18 октября 2018

Если вам интересно, как работает Smalltalk, посмотрите ответы @ blihp и @ leandro-caniglia.Также Deep Into Pharo ( 14.5 Контексты: представление выполнения метода ) содержит информацию о Context (с именем MethodContext до Pharo 3).

Если вы хотитеПоэкспериментируйте с ним, по крайней мере, в Pharo, псевдопеременная thisContext дает доступ к текущей точке выполнения.Вы можете указать:

thisContext copy inspect.

в своем методе, чтобы увидеть, какую информацию вы можете получить о конкретной точке выполнения.Эта информация включает отправителя.

Но если вам интересно, следует ли вам регулярно обращаться к отправителю сообщения в ваших методах, ответ будет нет .Если вам нужно знать объект, отправляющий сообщение обычным методом, передайте отправителю (self) дополнительный параметр.

0 голосов
/ 18 октября 2018

Отправитель определяется и устанавливается во время выполнения при отправке сообщения.С точки зрения выполняемого в настоящее время метода, он отвечает на вопрос «как мы сюда попали?»В наиболее распространенном случае отправителем будет любой метод, который отправил сообщение, в результате которого был вызван текущий метод.(одним исключением может быть обработчик # doesNotUnderstand: , который перенаправляет сообщение в какое-то место, отличное от первоначально предназначенного пункта назначения) Например, в Squeak, если вы doIt на aMorph color: Color yellow израбочая область, отправитель будет UndefinedObject >> DoIt .Если вы отправили то же сообщение от MyObject >> myTestSender , отправителем будет MyObject >> myTestSender .

Теперь предположим, что вы завернули aMorph в прокси-объект myProxy, экземпляр MyProxyObject, и его метод doesNotUnderstand: перенаправляет все, что он получает, в базовый aMorph объект,В этом случае, когда вы делаете myProxy color: Color yellow, отправитель будет MyProxyObject >> doesNotUnderstand: .(если только ваш метод doesNotUnderstand: не управляет средой выполнения ... что он может делать, если это необходимо) Это на самом деле хороший пример того, когда вам может понадобиться посмотреть, кто является отправителем #color:: он вызывается, нооткуда вы не понимаете, поскольку прокси-сервер добавляет уровень косвенности, который может быть вам не очевиден.

Поэтому, чтобы узнать, кто является отправителем, вы можете добавить следующее в метод color::

Transcript show: thisContext sender asString.

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

Теперь это может поставить вопрос: "Что, черт возьми, это thisContext?"Это специальная переменная, представляющая вершину стека вызовов, и это то, что многим людям трудно поначалу сложить голову.См. Как Smalltalk управляет кадрами стека вызовов для получения дополнительной информации.

Добавление (надеюсь, это устранит любую путаницу между ответом Леандро и моим)

Ответ Леандро рассматривает sender как общий термин и рассматривает больший исторический контекст, в то время как мой - более современный Squeak / Pharo-centric и имеет очень специфическое значение.Я согласен с мнением Леандро о том, что термин отправитель является неоднозначным и не стандартизирован для разных реализаций (как доказывают наши разные ответы). Просто чтобы еще больше запутать воду, в Синей книге ссылки на отправитель говорит о контексте отправки ... который не является ни self, ни thisContext sender.Тем не менее, ссылки, упомянутые в комментариях к вопросу, были явными по своему значению (то есть thisContext sender), что обычно подразумевается при ссылке на код Squeak / Pharo.То, какой ответ является правильным, зависит от того, смотрите ли вы на конкретную реализацию Smalltalk (в этом случае правильное использование - это то, что выбрано для используемой вами реализации) или как более общий термин, когда речь идет об отсутствии конкретной реализации Smalltalk (в этом случае Леандро прав: он подлежит интерпретации, поскольку его использование было перегружено до почти бессмысленности)

...