Перейти к основному содержимому

5.08. Smalltalk

Разработчику Архитектору

Мы с вами изучили основы кода, и особенно важным было изучение ООП - объектно-ориентированного программирования. И когда речь идёт об ООП, мы должны поговорить о Smalltalk - это самый правильный язык с точки зрения ООП. Да, язык старый, но его знание подарит вам понимание ООП на максимальном уровне. Многие программисты даже оценят знание этого языка, так как считают, что в других языках ООП реализовано сильно хуже, или «криво». Форумы кишат «холиварами» на тему того - какой язык более «ООПшный».

Что ж, Smalltalk является объектно-ориентированным языком программирования с динамической типизацией. У него довольно интересная философия. Это первый «чистый» ООП-язык, который повлиял на Java, Ruby, Python, Swift, Objective-C и прочие. Можно сказать, что это даже не только язык, а образ мышления, и если вы знаете Smalltalk - вы знаете суть ООП.

Особенности работы

Smalltalk:

  • объектно-ориентированный;
  • динамический;
  • интерпретируемый;
  • рефлексивный (может исследовать и модифицировать себя);
  • интерактивный - программирование в режиме диалога с системой.

Он относится к семейству языков с высокой степенью мета-возможностей, наряду с Lisp, Self и современными динамическими языками.

Smalltalk - один из самых влиятельных проектов в истории вычислений, и не из-за широкого использования, а потому что он впервые реализовал идеи, которые сегодня кажутся нам естественными:

  • Всё в программе - объект;
  • Программирование - это не написание кода, а взаимодействие с живой системой;
  • Среда разработки - не отдельный инструмент, а часть самой программы.

Технически, принципы ООП здесь доведены до логического предела. Здесь нет примитивных типов, операторов или статических конструкций. Только объекты и сообщения, которыми они обмениваются.

В отличие от большинства языков, где код пишется в редакторе, компилируется и запускается отдельным процессом, Smalltalk работает иначе. Работа с программой здесь представляет собой не обычный запуск, а своего рода «жизнь» внутри неё, ведь всё состояние системы - код, объекты, переменные, окна интерфейса - всё сохраняется в образе. Это образ системы (System Image), бинарный файл, содержащий полную копию работающей среды.

Вы можете изменить код, отлаживать, создавать объекты - и всё это сохранится при следующем запуске. Нет понятия «перезапуск приложения» - есть продолжение работы с того же места. Это как если бы ваша IDE, запущенные процессы и данные были бы одним целым. К примеру, вы исправили баг в отладчике, сохранили исправление, закрыли систему — а через неделю, открыв её снова, продолжаете с того же момента.

Smalltalk работает на виртуальной машине - VM, это программа, которая интерпретирует байт-код и управляет образом. VM отвечает за выполнение кода, управление памятью, графический интерфейс и взаимодействие с ОС. Это, кстати единственная часть системы, не написанная на самом Smalltalk (обычно на C/C++, традиционных системных языках). Всё остальное - включая сам компилятор, отладчик и редактор, написано на Smalltalk и работает внутри образа.

Smalltalk - язык с полной динамической типизацией, где типы проверяются во время выполнения, а не на этапе компиляции. Переменная не имеет типа — тип определяется по объекту, на который она ссылается. Это позволяет писать гибкий, адаптивный код, но требует от программиста большей ответственности.

Бывают языки строго типизированные, которые требуют указать тип, выделят память согласно правилам, и в случае несоответствия типов будут «ругаться». А динамически типизированные языки подразумевают, что платформа «сама разберётся», что за тип данных, главное их ей дать.

Smalltalk здесь реализуют концепцию интересным образом. Все типы данных здесь - числа, строки, классы, методы, блоки кода - всё является объектом, даже true, false. Имеется полная интроспекция - любой объект может рассказать о себе, кто его класс, какие его переменные, какие методы он поддерживает.

И самое необычное - здесь почти нет ключевых слов (всего их около шести).

В большинстве языков мы, как программисты, говорим «вызвать метод», что даёт команду и обращается к соответствующему блоку кода. В Smalltalk немного иначе - здесь «посылается сообщение». Любому объекту может быть послано любое сообщение. Что будет дальше — зависит от того, понимает ли объект это сообщение.

Давайте наконец посмотрим как выглядит язык:

42 factorial           "отправляем сообщение 'factorial' объекту 42"
'hello' size "отправляем 'size' строке"
(3 > 5) ifTrue: [ 'yes' ] ifFalse: [ 'no' ] "отправляем условное сообщение"

Если вы знаете или работали хоть с одним современным языком, то заметите сильную разницу в стиле и синтаксисе. Представьте что всё здесь - сообщения и объекты. Мы указываем объект и указываем сообщения. Если объект не понимает сообщение, он получает специальное сообщение doesNotUnderstand:, и вы можете перехватить его — это основа для динамического поведения, проксирования, DSL.

Smalltalk кроссплатформенный, и современные реализации работают как на Windows, так на macOS и Linux. VM обеспечивает абстракцию от операционной системы. Образы переносятся между платформами без изменений.

Совместимости с современными программами напрямую нет, ведь Smalltalk не компилируется допустим в .exe. Но есть интеграция с C через FFI (Foreign Function Interface), можно запускать внешние процессы.

В Smalltalk нет внешней IDE. Всё, что нужно, встроено.

Компоненты языка:

  1. Браузер классов (Class Browser) позволяет просматривать и редактировать классы, методы, пакеты. Иерархия классов здесь визуальная, а навигация мгновенная. Можно открыть любой метод в системе — включая код самого отладчика.
  2. Отладчик (Debugger) работает при возникновении ошибок. Там можно увидеть стек вызовов, изменить код «на лету» и продолжить выполнение. Можно вставить новые переменные, изменить значения и продолжить. Словом, позволяет «вмешаться» в процесс.
  3. Инспектор объектов (Inspector) позволяет заглянуть внутрь любого объекта, просмотреть переменные экземпляра, изменить их, вызвать методы, что полезно для отладки и экспериментов.

Сборка мусора (Garbage Collection) здесь автоматическая, на основе поколений (generational GC), освобождает память от объектов, на которые больше никто не ссылается, и является прозрачной для программиста.

Код компилируется в байт-код виртуальной машины, а компиляция происходит на лету, при сохранении метода. Здесь нет отдельного этапа «сборки проекта». Современные VM (например, в Pharo) используют JIT-компиляцию (Just-In-Time) для ускорения. Часто исполняемый код переводится в нативный машинный код.

Современными реализациями языка являются:

  1. Pharo - открытая реализация, имеет отличную IDE, поддерживает веб-разработку и анализ кода, подходит для обучения и прототипирования.
  2. Squeak - открытый потомок оригинального ST-80 (Smalltalk-80), который используется в образовательных проектах (Etoys, Scratch изначально основан на Squeak).
  3. VisualWorks - коммерческая реализация от Cincom, используетс в промышленных системах (финансы, телеком), стабильная и имеет поддержку корпоративных приложений.
  4. GNU Smalltalk - реализация от проекта GNU.

Существуют и иные реализации, но для изучения рекомендуется обычно Pharo.