[Из песочницы] Язык программирования, помещающийся на почтовой открытке
Источник
Ральф Джонсон, один из членов «Банды четырёх», однажды показал, как синтаксис языка Smalltalk-80 можно уместить на почтой открытке. Сейчас, спустя почти 30 лет после появления первой версии Smalltalk, самым быстроразвивающимся диалектом Smalltalk является Pharo, почтовую открытку которого далее и разберём.
Объявление метода
exampleWithNumber: x
Методы объявляются в виде имяМетода: имяПараметра
и являются членами класса. Метод с несколькими параметрами объявляется так
rangeFrom: start to: end
Имя метода здесь rangeFrom:to:
, а имена параметров — start
и end
.
Декларация pragma
Pragma используется для аннотации метода. Эта аннотация может использоваться компилятором или другими методами как метаданные.
Комментарии
"A ""complete"" Pharo syntax"
Комментарии обозначаются кавычками. Кавычки внутри комментария обозначаются двойными кавычками.
Объявление локальной переменной
| y |
Локальные переменные используются в вычислениях внутри метода. Объявления типа переменной не требуется, поскольку Smalltalk — динамически типизированный язык.
Несколько переменных объявляются одним списком
| y x totalSum |
Объекты и сообщения
true & false not & (nil isNil)
Всё в Smalltalk является объектами, а объекты могут принимать сообщения. Порядок выполнения (то есть — отправки сообщений) — слева направо, но сообщения без параметров отправляются в первую очередь в соответствии с правилами приоритета, так что порядок вычисления здесь будет
(true & (false not)) & (nil isNil)
Правил приоритета в Smalltalk всего четыре: первыми отправляются сообщения в скобках, затем — унарные (без дополнительных параметров помимо самого объекта-получателя, например false not
), затем — бинарные (с одним дополнительным параметром, например 1 + 2
), затем — сообщения с несколькими параметрами (например 15 between: 1 and: 2
). Приоритетность выполнения обозначается простой схемой
скобки > унарные > бинарные > сообщения с несколькими параметрами
Эти правила действуют и для математических операций, так что результатом выполнения выражения
1 + 15 / 4 " = (1 + 15) / 4 "
будет 4
. Кстати nil
также является объектом и может принимать и отвечать на сообщения.
Условное выполнение и блоки кода
true & false not & (nil isNil)
ifFalse: [ self perform: #add: with: x ].
Условное выполнение реализуется отправкой сообщений ifTrue
, ifFalse
объекту-логическому значению. Аргументом этого сообщения является блок кода, обозначаемый квадратными скобками, который выполняется, если выполняется заданное условие.
Блоки Smalltalk также используются как анонимные функции:
sum := [ :x :y | x+y ]. " Блок x,y -> x+y "
sum value: 10 value: 25. " Вычисление блока, результат - 35"
Отправка сообщений самому себе
self perform: #add: with: x
Ключевое слово self
используется как ссылка на содержащий метод объект при отправке сообщений самому объекту. Здесь мы отправляем сообщение perform: with: с аргументами #add
и x
. Знаком #
обозначается строка-литерал, которая здесь используется как идентификатор метода.
Присвоение переменной
y := thisContext stack size + super size.
Присвоение переменной обозначается оператором :=
. Ключевое слово super используется для обращения к объекту суперкласса.
Все объекты Smalltalk наследуют либо от класса Object
, либо от своего суперкласса, который, в свою очередь, наследует от своего суперкласса или от класса Object
.
Статический массив
byteArray := #[2 2r100 8r20 16rFF].
byteArray
— переменная экземпляра класса, объявленная при объявлении класса. Массив byteArray состоит из целых чисел, записанных в разных системах счисления в виде
<основание>r<число>
Размер статических массивов фиксирован и задаётся во время компиляции. Индексация массивов начинается с 1
byteArray at: 2 " = 2r100 "
С самого начала Smalltalk был не только языком, но и интегрированной средой разработки со своей виртуальной машиной: классы и методы Smalltalk не хранятся в отдельных текстовых файлах, а сразу сохраняются в образе виртуальной машины и объявляются через интерфейс среды разработки. Например, класс Counter
объявляется в разделе классов как
Object subclass: #Counter
instanceVariableNames: ’count initialValue’
classVariableNames: ’’
package: ’MyCounter’
а его методы объявляются в разделе методов класса Counter
.
Динамический массив
{ -42 . #($a #a #'I''m' 'a' 1.0 1.23e2 3.14s2 1) }
Динамический массив создается во время выполнения программы.
Массивы могут содержать данные разных типов: первый элемент массива — число -42, второй элемент массива — массив с элементами разных типов:
$a
— символ «a»#a #'I''m'
— строки-литералы «a» и «I’m»'a'
— строка «a»1.0 1.23e2
— числа с плавающей точкой3.14s2
— десятичная дробь с масштабом 2
Циклы
{ -42 . #($a #a #'I''m' 'a' 1.0 1.23e2 3.14s2 1) }
do: [ :each |
| var |
var := Transcript
show: each class name;
show: each printString ].
Циклы в Smalltalk реализуются отправкой сообщения массиву с блоком, который будет выполняться на каждом элементе этого массива, что очень похоже на функциональный подход. На каждой итерации элемент массива передаётся как аргумент блоку, производящему над ним какие-то вычисления. В блоке в примере объявляется локальная переменная var, которой присвается результат отправки последнего сообщения show глобальному объекту Transcript
.
Интересной фишкой Smalltalk является возможность каскадирования сообщений: выражение
Transcript show: 'A'; show: 'B'.
последовательно выводит строки A
и B
в окно консоли Transcript
. Это эквивалентно коду
Transcript show: 'A'.
Transcript show: 'B'.
но позволяет избежать повторения имени объекта-получателя сообщений Transcript. Результатом каскадирования является ответ объекта на последнее сообщение.
Возврат значения из метода
^ x < y
Возврат значения обозначается символом ^
. В данном случае возвращается логическое значение — результат сравнения x < y
.