Краткий обзор языка программирования Nim

22 июня 2015

Вам доводилось когда-нибудь мечтать о языке, похожем на Scala, только без привязки к JVM и чтобы в нем было поменьше объектов? Или, возможно, как Python, только с типами и по скорости сравнимом с Си? Или, быть может, чтобы Rust имел человеческий синтаксис, поддерживал исключения и был в состоянии без помощи программиста понять, какие переменные класть в стек, а какие в кучу? Если что-то из названного верно, думаю, вам понравится Nim.

Основные сведения о Nim:

  • Язык раньше назывался Nimrod, потом сократили до Nim;
  • Создан товарищем по имени Andreas Rumpf в 2008-м году. Хотя язык уже довольно зрелый, он все еще продолжает разрабатываться, версии 1.0 пока что нет (UPD: Версия 1.0 вышла 23 сентября 2019);
  • Nim является мультипарадигменным языком. Он одновременно процедурный, объектно-ориентированный и функциональный, притом примерно поровну. Также есть поддержка метапрограммирования, и весьма мощная, а не так, для галочки;
  • Язык очень простой, можно освоить по туториалу на официальном сайте за считанные часы. Синтаксис мне больше всего напомнил Python, только с типами и без объектов на каждый чих;
  • В языке используется строгая статическая типизация. Есть REPL, вполне классические генерики и исключения. Вместо трейтов или интерфейсов язык предлагает концепты, которые, насколько я понимаю, являются значительно более мощным средством;
  • Язык транслируется в Си, C++, Obj-C, а потом компилируется в обычные бинарники. Благодаря этому Nim очень быстр, с легкостью использует любые сишные библиотеки и работает практически где угодно. Как оказалось, код на Nim отличается еще и довольно высокой скоростью компиляции. Кроме того, поддерживается трансляция и в JavaScript;
  • По умолчанию сборка мусора в Nim автоматическая, с использованием локальных куч, по одной на поток, и отложенного подсчета ссылок с дополнительными обходами для поиска циклов в тех структурах, где циклы возможны. Никаких фоновых процессов, собирающий мусор, в Nim нет. За счет всего это GC в Nim является, что называется, soft realtime, и никогда не делает stop the world. До выхода Nim 1.0 планируется добавить поддержку групп процессов с общей кучей. Кроме того, язык позволяет управлять памятью вручную, прямо как в Си. В этом случае данные размещаются в общей куче и лишены накладных расходов на копирование между процессами;
  • Нити в Nim — это обычные нити операционной системы, хранящиеся в пуле. За счет этого их создание и уничтожение дешевле, чем у обычных ниток. Но сами по себе эти нити дороже, чем потоки в Haskell или горутины в Go. Взаимодействуют нити при помощи асинхронных каналов или общей кучи, той, что с ручным управлением памятью. Ввод-вывод поддерживается как синхронный, так и асинхронный. Последний основывается на epoll в Linux и IOCP в Windows. Также в Nim есть футуры, похожие на футуры в Scala;
  • Имеет впечатляющую стандартную библиотеку. Есть менеджер пакетов под названием Nimble. Репозиторий централизованный, в виде JSON файла на GitHub — привет, Perl 6! Это хорошо, так как позволяет избежать проблемы с десятками форков одного пакета, как это случилось в мире Erlang. Готовых пакетов уже сейчас на удивление много. Есть клиенты для PostgreSQL, MySQL и MongoDB, легковесный веб-фреймворк Jester, биндинги к OpenGL и GTK, и много чего еще. Также, что касается инструментария, ведется работа над самописной IDE под названием Aporia;
  • В исходном коде на Nim запрещено использовать табуляцию. Ура, ну наконец-то кто-то до этого додумался! Поставил таб — все, код не компилируется;
  • Nim имеет null pointer’ы. Видимо, они нужны для взаимодействия с кодом на Си. Но также язык поддерживает и множество средств для нахождения сопутствующих ошибок, в том числе на этапе компиляции, например, аннотацию not nil. Насколько я понял, тут ситуация примерно как в случае со Scala и Java. Null есть, но на практике NPE может возникнуть только на границе взаимодействия языков или в чем-то вроде собственной реализации двусвязных списков;
  • Есть и ряд других примечательных особенностей. Компилятор имеет множество флагов, позволяющий, например, включать и выключать проверки на выход за границы массивов и такого рода вещи. По умолчанию в debug сборках такие проверки включаются по максимуму, а в release сборке отключаются. Есть еще система эффектов, при необходимости позволяющая сказать, что вот у этой функции нет побочных эффектов (код в стиле proc {.noSideEffect.} ...), вот эта никогда не бросает исключения, а вот эта бросает, но только такие-то;
  • Компилятор и библиотеки распространяются под лицензией MIT. За счет этого ваши собственные программы на Nim вы можете распространять под какой угодно лицензией;

Теперь давайте попробуем поиграться со всем этим.

На официальном сайте доступно описание нескольких способов установки компилятора Nim. Так, например, выглядит сборка из исходников на GitHub:

git clone -b master git://github.com/Araq/Nim.git
cd Nim
git clone -b master --depth 1 git://github.com/nim-lang/csources
cd csources && sh build.sh
cd ..
bin/nim c koch
./koch boot -d:release

Путь до Nim/bin прописываем в переменную окружения $PATH. Заценим REPL:

$ nim i

>>> echo("Hello, world!")
Hello, world!

Для выхода используйте сочетание Ctr+D.

Также есть полезная утилита nimsuggest, которая, в частности, используется в Aporia. О том, как правильно собирать nimsuggest, мне удалось узнать только при помощи IRC-канала #nim во FreeNode:

cd $NIM_PATH/compiler/nimsuggest
nim c -d:release nimsuggest.nim
cp nimsuggest ../../bin/

Ставим Nimble:

git clone https://github.com/nim-lang/nimble
cd nimble
nim c -r src/nimble install

Каталог ~/.nimble/bin/ также добавляем в $PATH. Проверяем, что все работает:

nimble update
nimble list
nimble install rbtree

Установка и запуск Aporia:

nimble install aporia@#head
aporia

Если увидите ошибку:

could not load: libgtksourceview-2.0.so(|.0)

… исправляем так:

sudo apt-get install libgtksourceview2.0-dev

Вот так примерно Aporia выглядит после запуска:

Aporia, текстовый редактора для Nim

По возможностям, правда, Aporia оказалась ближе к обычному текстовому редактору, чем IDE. Подсветка синтаксиса нормальная. Притом, подсветка есть не только для Nim. В настройках можно включить автокомплит, но работает он пока что как-то слабенько, не все методы предлагает на выбор. Есть табы, но я не нашел хоткеев для переключения между ними. Даже элементарного фолдинга нет. Кроме того, я словил core dump при попытке использовать goto definition, после чего Aporia не запускалась, пока я вручную не прибил nimsuggest. Как видите, что касается Aporia, тут пока все очень сыро, и по возможностям сильно уступает простому Vim.

Создание нового проекта на Nim происходит следующим образом:

mkdir hello_world
cd hello_world
nimble init hello_world

В hello_world.nimble можно изменить название проекта, описание, лицензию и тд. Дописываем:

bin = "hello_world"

Создаем hello_world.nim следующего содержания:

echo("Hello, world!")

Собираем, запускаем:

nimble build
./hello_world

В общем и целом, что касается сборки, тут все примерно как обычно.

Опасения в отношении Nim лично у меня довольно традиционные — отсутствие вакансий, небольшой размер сообщества, сырость библиотек и инструментов, тот факт, что язык все еще продолжает немного изменяться, отсутствие каких-либо success stories, отсутствие большой и серьезной компании, которая продвигала бы все это хозяйство, отсутствие нормальной IDE, и тот факт, что создание такой IDE усложняется наличием в языке макросов. Также меня немного печалит отсутствие в Nim нормальных легковесных процессов. С другой стороны, подозреваю, что не так-то просто их сделать, сохранив при этом в языке возможность использовать как синхронный, так и асинхронный ввод-вывод. Также подозреваю, что при желании их можно успешно реализовать на макросах Nim, ибо по своей мощи они, судя по всему, не уступают макросам Lisp.

Несмотря на все это, язык выглядит очень и очень годно. На мой взгляд, куда более годно, чем тот же Rust с этими его постоянными Arc<T> и Box<T>. Зато операционные системы писать можно, ведь нам с вами так не хватает новых операционных систем! Так о чем я? Да, уже сейчас количество готовых библиотек для Nim впечатляет. Не уверен, что у Erlang наберется столько же. Хотя, конечно, остается открытым вопрос о качестве этих библиотек. Также подкупает наличие очень подробной документации и отзывчивость сообщества, по крайней мере, на канале #nim во FreeNode.

Не знаю, выстрелит ли Nim, но мне очень хочется, чтобы выстрелил. Уже сейчас мне очень хочется пописывать на нем pet project’ы. И, кто знает, может через годик-другой мне даже захочется переписать на нем какой-нибудь не самый критичный кусочек боевой системы.

Ссылки по теме:

А что вы думаете о Nim?

Метки: , .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.