Защо методите се връщат по подразбиране в Smalltalk?

Заден план

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

Например, като се има предвид този метод:

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

Оценяване (не го "отпечатайте") това:

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

Ако ‹print-it› се извърши до последното извикване, тогава резултатът ще бъде самият екземпляр.

Въпроси

  • Защо това е проектирано по този начин?
  • Каква е идеята зад него?
  • Какъв беше философският фон?
  • Какви са практическите ползи от него? Дали е за улесняване на веригата на методите?

person Sebastian N.    schedule 27.12.2012    source източник
comment
Интересна бележка по свързана тема: блоковете връщат резултата от последния израз.   -  person Lukas Renggli    schedule 27.12.2012


Отговори (5)


Една много проста причина все още не е посочена: във виртуалната машина връщането на себе си е по-просто и по-ефективно от връщането на всеки друг обект.

Байтовите кодове на Smalltalk реализират стекова машина. Това означава, че аргументите се предават, като се поставят в стек, вместо да се поставят в регистри. В допълнение към аргументите, изброени в сигнатурата на метода, винаги се предава скрит аргумент, който е получателят на съобщението. Така че дори за унарни методи (тези без аргументи) приемникът се избутва в стека, след което методът се изпълнява и стойността на приемника в стека е начинът, по който методът познава "себе си". Чрез връщане на „self“, ако не е даден изричен израз за връщане, VM може просто да остави „self“ oop в стека, което спестява поне една операция за съхранение на паметта. Така че от гледна точка на ефективност и простота, връщането на "self" е най-елегантното нещо, което трябва да направите.

person Vanessa Freudenberg    schedule 30.12.2012
comment
Моето предчувствие е, че успяхте. Това звучи точно като вида оптимизации, които намирате в оригиналната реализация на Smalltalk-80. - person akuhn; 03.01.2013

Синята книга на Smalltalk-80 (Езикът и неговата реализация) не казва нищо относно защо връща приемник по подразбиране.

Има обаче цитат на страница 27 (Раздел „Връщане на стойности“), който може да ви помогне:

„Дори ако не е необходимо информация да бъде съобщена обратно на подателя, получателят винаги връща стойност за израза на съобщението. Връщаната стойност показва, че отговорът на съобщението е завършен. (...)“

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

Има някои добри практики за това какво да се върне в зависимост от намерението на съобщението, но това е предмет на друга история.

person Esteban A. Maringolo    schedule 27.12.2012

Не съм създател на smalltalk, но изглежда, че това е най-доброто нещо, което можете да направите.

Например, ако ще изпълните:

var := myInstance myMethod.

тогава въпросът е: какъв искаш да стане var? Едната опция ще бъде nil. Но е малко объркващо, защото работите с дефинирани обекти и nil всъщност е недефиниран. Така че можете да го третирате, докато присвоявате myInstance на var и просто извиквате myMethod по пътя. Също така това вероятно може да се третира като стенограма за

 var := myInstance myMethod; yourself.

Ако погледнете отвътре, тогава от всички налични данни за самия обект най-подходящото нещо вероятно също е self. Още веднъж, nil може да се върне, но вече съм казвал мнението си за него.

В Smalltalk няма такова нещо като метод void, който не връща нищо, и няма проверка на типа. Така че методът просто трябва да върне нещо. Все едно Обектът казва:

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

Лично аз смятам, че връщането на nil също може да е добро и Objective-C приложенията използват nil неща много често, но Smalltalk е направен по този начин и мисля, че е доста добро решение.

person Uko    schedule 27.12.2012

Методите се връщат по подразбиране по няколко причини.

  1. Методите на Smalltalk трябва да върнат нещо
  2. себе си е най-лесният обект за връщане
  3. self е най-бързият обект за връщане
  4. Връщането на себе си позволява няколко модела на проектиране да работят естествено

Нека обясня #4 малко повече. Един общ модел за инициализация на обект е да се дефинира нов метод за класа, който изглежда така:

new
   ^super new initialize

Този модел зависи от връщането на себе си при инициализация. Не е нормално обаче да добавяте ^self в края на метод за initialize. Не е необходимо, защото методът така или иначе ще се върне сам.

В крайна сметка връщането на себе си е просто естествен избор по подразбиране, като се има предвид, че трябва да върнете нещо.

person David Buck    schedule 05.01.2013
comment
Да, връщането на self помага за верижното свързване на съобщения. Идеята може да се намери и в (някои) Java методи. - person U. Windl; 27.05.2021

Идвайки от Java, знаете за NullPointExceptions, когато работите с недефинирани върнати стойности. Освен това вашият код трябва да извършва условна проверка за null тук и там.

Затова бях щастлив да намеря върната стойност за всяко извикване на метод или съобщение, изпратено в Smalltalk. Ако решите всеки метод да връща някаква стойност, ще попитате каква може да бъде стойността ви по подразбиране. Самият обект (self) е много естествен начин за използване като стойност по подразбиране. Или да попитам обратното: каква би могла да бъде по-добра възвръщаема стойност?

person pintman    schedule 27.12.2012