Smalltalk часто воспринимают как язык из музея: был до Java, остался в учебниках. На самом деле Pharo — современная открытая реализация Smalltalk. Её особенность в том, что программа живёт не в файлах, а в образе: вы меняете классы и методы прямо в запущенной среде, сразу проверяете гипотезу и сохраняете результат.

Почему Smalltalk удивляет

В Smalltalk нет разделения на код и среду выполнения. Есть образ — файл со всеми объектами, классами и методами, — и виртуальная машина, которая его исполняет. Вы пишете выражение в Playground и сразу получаете результат. Если выражение падает, открывается отладчик с полным стеком: метод можно править и продолжать, не перезапуская программу.

Отсюда мгновенная обратная связь. Отсюда же сложность: исходники — не главный артефакт, а образ нужно версионировать иначе, чем папку с файлами.

Установка Pharo

Самый быстрый способ на Linux и macOS — официальный скрипт zeroconf. Он скачивает виртуальную машину, образ и файл изменений в текущую папку.

mkdir ~/pharo && cd ~/pharo
curl https://get.pharo.org/64/ | bash
./pharo Pharo.image eval "3 factorial"
./pharo Pharo.image

Третья команда проверяет запуск без графики и печатает 6, четвёртая открывает среду с окнами. Для повседневной работы удобнее Pharo Launcher: он хранит несколько образов и создаёт чистые копии. На Windows это практически безальтернативный вариант.

Всё есть объект

Синтаксис Smalltalk короткий, потому что управляющих конструкций нет: if, while и циклы — обычные сообщения объектам. Сообщения бывают унарные (factorial), бинарные (+, *) и ключевые (at:put:). Порядок вычисления — слева направо, скобки его меняют.

3 factorial.                                  "6"
'hello' size.                                 "5"
#(1 2 3) inject: 0 into: [ :sum :each | sum + each ].
(1 to: 5) select: [ :n | n odd ].             "OrderedCollection(1 3 5)"
Transcript showln: 'готово'.

Результат выражения Playground показывает справа. В двойных кавычках — комментарий, $a — отдельный символ, #(1 2 3) — литерал массива. Точка разделяет выражения, точка с запятой означает каскад.

Блоки и коллекции

Блок — замыкание в квадратных скобках. Оно не выполняется сразу, а передаётся как объект: его можно сохранить, вызвать через value, вернуть из метода. На блоках построены все итераторы коллекций.

| numbers doubled |
numbers := #(1 2 3 4 5).
doubled := numbers collect: [ :each | each * 2 ].
numbers do: [ :each | Transcript showln: each ].
(numbers select: [ :each | each even ]) size.  "2"

Вертикальные черты объявляют временные переменные. Коллекции богатые, и почти любая задача решается цепочкой select:, collect:, detect:, inject:into: без циклов со счётчиком.

Свой класс за минуту

Класс создаётся отправкой сообщения subclass: существующему классу. Методы добавляют из Playground или браузера классов.

Object subclass: #Counter
  instanceVariableNames: 'value'
  classVariableNames: ''
  package: 'Shop'.

Counter compile: 'increment
  value := (value ifNil: [ 0 ]) + 1'.

Counter compile: 'value
  ^ value ifNil: [ 0 ]'.

Counter new increment; increment; value.   "2"

Селектор, тело, возврат через ^ — вот и весь метод. ifNil: — сообщение, а не конструкция языка, поэтому else-ветка передаётся блоком. Каскад increment; increment; value вызывает три метода у одного объекта и возвращает результат последнего.

Инструменты среды

Pharo — это ещё и набор инструментов из меню World:

  • Playground — блокнот для выражений, главное окно экспериментов.
  • System Browser — навигация по пакетам, классам и методам, правка на ходу.
  • Inspector — состояние любого объекта по полям, с изменением значений.
  • Debugger — открывается при ошибке, позволяет править метод и повторять выражение.
  • Finder — поиск классов и методов по содержимому.
  • TestRunner — запуск тестов и просмотр результатов.

Отладчик попробуйте первым делом: поставьте self halt, вызовите метод и посмотрите на стек. Это главный аргумент в пользу Smalltalk для обучения.

Пакеты и зависимости

Сторонний код ставится через Metacello — менеджер пакетов, который читает baseline-описание из Git-репозитория.

Metacello new
  baseline: 'MyApp';
  repository: 'github://myorg/myapp:main';
  load: 'core'.

Для HTTP есть Zinc, для JSON — NeoJSON, для сериализации — STON. Этого хватает, чтобы написать небольшой сервис на Seaside или голом Zinc.

Тесты

Тесты пишутся как классы-наследники TestCase и запускаются из TestRunner или Playground.

TestCase subclass: #CounterTest
  instanceVariableNames: ''
  classVariableNames: ''
  package: 'Shop'.

CounterTest compile: 'testIncrement
  | counter |
  counter := Counter new.
  counter increment; increment.
  self assert: counter value equals: 2'.

CounterTest suite run.

setUp выполняется перед каждым тестом, tearDown — после. Проверок немного: assert:, assert:equals:, deny:, should:raise:. Этого достаточно: тестируют поведение объектов, а не глобальное состояние.

Сохранение и запуск без графики

Образ можно сохранить вместе с кодом и запускать на сервере как обычный процесс. Команда save создаёт копию, флаг —headless отключает окна.

./pharo Pharo.image save shop
./pharo --headless shop.image eval "Smalltalk version"
./pharo --headless shop.image eval "ShopServer start"

Для продакшена образ собирают в CI, кладут рядом с VM и запускают через systemd. Образ содержит и код, и данные, поэтому его нельзя перезаписать на ходу: процесс останавливают, затем заменяют файлы. Часто код грузят при старте из Git через Metacello, а образ держат минимальным.

Диагностика и типичные проблемы

  • Smalltalk version и Smalltalk vm version — версия образа и виртуальной машины.
  • Smalltalk image imagePath — откуда запущен образ, полезно при путанице с копиями.
  • Из cron нет доступа к дисплею, поэтому используйте —headless.
  • Ошибка «image is read-only» — образ в папке без прав на запись, скопируйте его.

Если среда не стартует, проверьте файл .changes рядом с образом и совпадение версий VM и образа. При переносе копируйте оба файла, а не только image.

Кому это нужно

Pharo выбирают для обучения ООП, прототипов, исследовательских проектов и нишевых веб-приложений. Он не заменит Python или Go: вакансий мало, экосистема небольшая. Понимание сообщений, блоков и живой среды меняет взгляд на любой язык. Для продакшена из Pharo получается компактный сервис без внешних зависимостей.

Итог

Smalltalk в Pharo — рабочая среда с мгновенным циклом правок и мощным отладчиком. Начните с zeroconf-установки, выполните выражения в Playground, создайте класс Counter и запустите тест. Затем переходите к Metacello и Iceberg и попробуйте собрать HTTP-сервис на Zinc. Опыт системы, где всё является объектом, пригодится и в другом стеке.

Насколько публикация полезна?

Нажмите на звезду, чтобы оценить!

Средняя оценка 0 / 5. Количество оценок: 0

Оценок пока нет. Поставьте оценку первым.

Поделиться: Telegram ВКонтакте