Сообщения
Smalltalk определяет три основные формы сообщений (и связанных с ними методов): унарные, бинарные и заданные ключевым словом. Унарные сообщения задают вызовы подпрограмм без аргументов:
acc1 balanceЗдесь сообщение balance посылается объекту, связанному с acc1. Запись эквивалентна нотации acc1.balance, используемой в Simula и в данной книге. Сообщения могут, как в данном случае, возвращать значения. Сообщения с ключевыми словами вызывают подпрограммы с аргументами:
point1 translateBy: vector1 window1 moveHor: 5 Vert: -3Заметьте, используется ключевой способ при передаче аргументов. При этом частью установленного стиля Smalltalk является объединение имени вызываемого сообщения и первого аргумента, что порождает такие идентификаторы, как translateBy или moveHor. Соответствующая запись в Simula или нашей нотации была бы point1.translate (vector1) и window1.move (5, -3).
Бинарные сообщения, похожие на инфиксные функции Ada и нотацию этой книги, служат для примирения подхода "все является объектом" с традиционными арифметическими нотациями. Большинство людей, по крайней мере старшего поколения, изучавших арифметику до объектной технологии, скорее напишут 2+3, чем:
2 addMeTo: 3Бинарные сообщения Smalltalk дают первую форму записи как синоним второй. Однако здесь есть заминка: приоритет операций. Выражение a + b * c здесь означает не то, что вы думаете - (a + b) * c. Для изменения порядка разработчики могут использовать скобки. Унарные сообщения предшествуют по старшинству бинарным, так что window1 height + window2 height имеет ожидаемое значение.
В отличие от Simula и нотации данной книги классы Smalltalk могут экспортировать только методы (подпрограммы). Для экспорта атрибутов, являющихся закрытыми, необходимо написать функцию, дающую доступ к их значениям. Типичным примером является:
x | | xx y | | yy scale: scaleFactor | | xx <- xx * scaleFactor yy <- yy * scaleFactorМетоды x и y возвращают значения переменных экземпляров (атрибутов) xx и yy. Стрелка вверх означает, что следующее выражение - это величина, возвращаемая методом отправителю соответствующего сообщения.
Метод scale имеет аргумент scaleFactor. Вертикальные полосы | | будут ограничивать локальные переменные, если они есть.
Наследование - важная часть подхода Smalltalk, но кроме некоторых экспериментальных реализаций, оно ограничивается единичным наследованием. Чтобы дать возможность при переопределении метода вызывать оригинальную версию, Smalltalk позволяет разработчику ссылаться на объект, рассматриваемый как экземпляр класса родителя, посредством имени super, как в:
aFunction: anArgument |...| ... super aFunction: anArgument ...Интересно сравнить этот подход с техникой, основанной на Precursor, и дублирующим наследованием.
Всякое связывание в Smalltalk - динамическое. В отсутствии статического связывания, ошибки, вызванные пересылкой сообщения объекту, не снабженному соответствующим методом для его обработки, не будут обнаружены компилятором и приведут к сбою во время выполнения.
Динамический контроль типов делает неуместными некоторые концепции, развитые ранее в этой книге: Smalltalk не нуждается в языковой поддержке универсальности, поскольку структуры, подобные стеку, могут содержать элементы любого типа без какой бы то ни было статической проверки согласованности. Становятся ненужными отложенные подпрограммы, поскольку для вызова x f (эквивалент x.f) нет статического правила, требующего, чтобы определенный класс обеспечивал метод f. Если класс C получает сообщение, соответствующее методу, чьи эффективные определения появляются только в потомках C, то Smalltalk лишь обеспечит возбуждение ошибки во время выполнения, Например, в классе FIGURE можно реализовать rotate таким образом:
rotate: anAngle around: aPoint | | self shouldNotImplementМетод shouldNotImplement включается в общий класс объект и возвращает сообщение об ошибке. Нотация self означает текущий объект.