Почему методы возвращают "self" по умолчанию в Smalltalk?

Фон

В Smalltalk, если вы ничего явно не возвращаете, то передача сообщения оценивается получателю (или "себе" в контексте сообщения).

Например, учитывая этот метод:

MyClass >> myMethod
  Transcript show: 'hello'; cr.

Оценивая (doint "print-it") это:

| myInstance |
myInstance := MyClass new.
myInstance myMethod.

Если выполнено до последнего вызова, то результатом будет сам экземпляр.

Вопросы

  • Почему это было разработано таким образом?
  • Какая идея стоит за этим?
  • Каков был философский фон?
  • Каковы практические выгоды от этого? Это для облегчения цепочки методов?

5 ответов

Решение

Одна очень простая причина еще не указана: в Виртуальной машине возвращать себя проще и эффективнее, чем возвращать любой другой объект.

Байт-коды Smalltalk реализуют стековую машину. Это означает, что аргументы передаются путем помещения их в стек, а не в регистры. В дополнение к аргументам, перечисленным в сигнатуре метода, всегда передается скрытый аргумент, который является получателем сообщения. Таким образом, даже для унарных методов (без аргументов) получатель помещается в стек, затем метод выполняется, и значение получателя в стеке определяет, как метод знает "себя". Возвращая "self", если явного оператора return не задано, виртуальная машина может просто оставить "self" в стеке, что сохраняет как минимум одну операцию сохранения памяти. Таким образом, с точки зрения эффективности и простоты, возвращение "я" - самая элегантная вещь.

Синяя книга Smalltalk-80 ("Язык и его реализация") ничего не говорит о том, почему он возвращает получателя по умолчанию.

Однако на странице 27 есть цитата (раздел "Возвращение значений"), которая может вам помочь:

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

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

В зависимости от цели сообщения есть несколько примеров хорошей практики для возвращения, но это тема другой истории.

Я не создатель болтовни, но, похоже, это лучшее, что можно сделать.

Например, если вы выполните:

var := myInstance myMethod.

тогда вопрос: что ты хочешь var становиться? Один вариант будет nil, Но это немного сбивает с толку, потому что вы работаете с определенными объектами и nil на самом деле неопределенный. Таким образом, вы можете относиться к этому, как вы назначаете myInstance в var и просто вызываю myMethod по пути. Также это можно рассматривать как сокращение для

 var := myInstance myMethod; yourself.

Если вы посмотрите изнутри, то из всех данных, доступных самому объекту, наиболее подходящая вещь, вероятно, также self, Еще раз, nil можно вернуть, но я уже высказал свое мнение по этому поводу.

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

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

Лично я думаю, что возвращение nil может быть хорошо, и приложения Objective-C используют nil очень часто, но Smalltalk сделан таким образом, и я думаю, что это довольно хорошее решение.

Методы возвращают себя по умолчанию по нескольким причинам.

  1. Методы Smalltalk должны возвращать что-то
  2. Самость - это самый легкий объект для возвращения
  3. Самость - самый быстрый объект для возвращения
  4. Возврат себя позволяет нескольким шаблонам дизайна работать естественно

Позвольте мне объяснить #4 немного больше. Один общий шаблон для инициализации объекта - это определение нового метода для класса, который выглядит следующим образом:

new
   ^super new initialize

Этот шаблон зависит от инициализации, возвращающей себя. Однако ненормально добавлять ^ self в конце метода инициализации. Это не нужно, потому что метод все равно вернет себя.

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

Исходя из Java, вы знаете об исключениях NullPointException при работе с неопределенными возвращаемыми значениями. Кроме того, ваш код должен выполнять условную проверку на ноль здесь и там.

Поэтому я был рад найти возвращаемое значение для каждого вызова метода или сообщения, отправленного в Smalltalk. Если вы решите, чтобы каждый метод возвращал какое-то значение, вы спросите, каким может быть ваше значение по умолчанию. Сам объект (self) является очень естественным способом использования в качестве значения по умолчанию. Или спросить наоборот: что может быть лучшим возвращаемым значением?

Другие вопросы по тегам