5.08. Особенности синтаксиса
Особенности синтаксиса
Синтаксис Smalltalk — один из самых минималистичных в истории.
Здесь всего 6 ключевых слов: true, false, nil, self, super, thisContext.
Нет специальных конструкций для циклов — есть методы вроде timesRepeat: или do:.
10 timesRepeat: [ Transcript show: 'Hello' ].
Это противоположно языкам вроде C# или Java, где синтаксис насыщен ключевыми словами и конструкциями. В Smalltalk поведение не вшито в язык — оно делегировано объектам. Поэтому вам и учить особо ничего не нужно.
true это единственный экземпляр класса True. Он представляет логическое «истина», как и везде. Пример:
(x > 0) ifTrue: [ ... ]
false - единственный экземпляр класса False. Логическое «ложь». Пример:
(x < 0) ifFalse: [ ... ]
nil - единственный экземпляр UndefinedObject, обозначает отсутствие значения. Пример:
var := nil
self - это ссылка на текущий объект (аналог this в Java/C#). Пример:
^ self name
super - вызов метода у родительского класса. Помните «суперклассы»? Как раз оно. Пример:
super initialize
thisContext - ссылка на текущий контекст выполнения (стек-фрейм).
Что важно - это не операторы и не управляющие конструкции, не типы данных, это просто объекты или ссылки, встроенные в систему.
В большинстве языков проверка на то, что x>0, к примеру, в Java, будет такая:
if (x > 0) {
System.out.println("Positive");
}
В Smalltalk:
(x > 0) ifTrue: [ Transcript show: 'Positive' ]
Как можно обратить внимание, нет ключевого слова if. Так же нет for, while, class, function, return — всё это реализуется через сообщения и объекты. В данном случае, x>0 - это выражение, которое возвращает объект true или false. Мы посылаем этому объекту сообщение ifTrue.
true выполняет блок, а false игнорирует. То есть, условие не является синтаксической конструкцией, а представляет поведение объекта. То же самое с циклами:
10 timesRepeat: [ Transcript show: 'Hello' ]
Звучит как английское выражение да? Повтори 10 раз - тут 10 это объект, timesRepeat - сообщение, а [] - блок кода, тоже объект. И нет циклов вроде for.
В Smalltalk каждое выражение возвращает объект. Даже присваивание:
x := 5 "возвращает 5"
Даже блок:
[ 2 + 3 ] "возвращает сам блок (ещё не выполнен)"
Выполнение блока:
[ 2 + 3 ] value "возвращает 5"
Это позволяет строить цепочки выражений:
(3 + 4) factorial negated abs "7! = 5040, negated = -5040, abs = 5040"
Каждое сообщение возвращает объект, на который можно послать следующее сообщение. А блоки - это не анонимные функции, а полноценные объекты.
Синтаксис у блоков таков:
[ :параметры | тело ]
Примеры:
[ Transcript show: 'Hello' ] "без параметров"
[ :x | x * x ] "с одним параметром"
[ :a :b | a + b ] "с двумя"
Блоки можно хранить в переменных:
square := [ :x | x * x ].
Передавать как аргументы:
numbers do: [ :n | Transcript show: n printString ].
Выполнять:
square value: 5 "→ 25"
Это предшественник лямбд в Java, замыканий в Python, стрелочных функций в JS.
А как посылаются сообщения?
Весь синтаксис Smalltalk строится вокруг трёх форм посылки сообщений.
- Унарные сообщения. У них нет параметров, имя - одно слово, и они имеют высокий приоритет. Пример:
42 factorial
'hello' size
Date today
Здесь объект 42 отправляет себе сообщение factorial.
- Бинарные сообщения. Это что-то вроде операторов из символов
+,-,*,/,>,<,=,,и др, но это просто сообщения.
3 + 4
'hello' , ' world' "конкатенация строк"
x > 0
3+4 - объект 3 получает сообщение 4 с аргументом 4.
Можно определять свои:
Number >> @@
^ self abs
И теперь (-5) @@ будет 5.
- Ключевые сообщения. Имя сообщения разделено на части, каждая из которых заканчивается на : (двоеточие), а каждая часть принимает один аргумент:
'Hello' indexOf: $e startingAt: 3
Здесь сообщение это indexOf:startingAt: а аргументы - $e и 3.
Другие примеры:
String with: $A "создать строку из символа"
Dictionary at: 'key' put: 'value'
Point x: 10 y: 20
Сначала выполняются унарные, потом бинарные, потом ключевые. Внутри группы слева направо, а скобки меныяют порядок:
3 + 4 * 5 "→ (3 + 4) * 5 = 35"
3 + (4 * 5) "→ 23"
Знаки препинания тоже имеют свои значения:
. (точка) это разделитель выражений. Как точка с запятой в C/Java. К примеру:
x := 5. y := 10
: (двоеточие), как мы выявили ранее, указывает на параметр в ключевом сообщении.
` (апостроф) разделяет объявление переменных в блоке или методе.
[] (квадратные скобки) определяют блок кода.
() (круглые скобки) группируют выражения.
:= (двоеточие и равно) определяют присваивание:
count := 0
" (двойные кавычки) определяют комментарий.
Как можно заметить, нет фигурных скобок, нет ; в конце строк, нет return.