Релиз Ruby 3.3.0: что появилось нового в языке программирования и что изменилось

47f1afe8ef8ff0a564113635988d141e.jpg

На днях появился новый релиз динамического объектно ориентированного языка программирования Ruby 3.3.0. Он вобрал в себя лучшие возможности многих других ЯП, включая Perl, Java, Python, Smalltalk, Eiffel, Ada и Lisp. Что касается кода проекта, то он распространяется под лицензиями BSD (2-clause BSDL) и Ruby, которая ссылается на последний вариант лицензии GPL и полностью совместима с GPLv3. Подробности — под катом.

Что изменилось и что добавили?

5cb0909264f06617c102f00e741ef315.png

  • Одно из важных изменений — оптимизация производительности JIT-компилятора YJIT. Он развивается разработчиками платформы электронной коммерции Shopify. Делается это в рамках проекта по улучшению производительности Ruby-программ, которые используют фреймворк Rails и вызывают очень много методов. YJIT использует версионирование базовых блоков (LBBV — Lazy Basic Block Versioning) вместо обработки методов целиком и реализован в форме интегрированного JIT-компилятора, написанного на языке Rust. Благодаря LBBV JIT вначале компилирует только начало метода, а оставшуюся часть компилирует через некоторое время, после того как в процессе выполнения будут определены типы используемых переменных и аргументов.

  • При проведении тестов, включая выполнение эмулятора Optcarrot, производительность при использовании компилятора примерно в три раза выше выполнения посредством интерпретатора. Также стоит отметить, что в новой версии обеспечено выделение регистров для стековых операций виртуальной машины. Кроме того, расширен спектр компилируемых вызовов с необязательными аргументами, реализовано inline-развёртывание базовых и специализированных методов, добавлены отдельные оптимизации для операций «Integer#*», «Integer#!=», «String#!=», «String#getbyte», «Kernel#block_given?», «Kernel#is_a?», «Kernel#instance_of?» и «Module#===». Значительно увеличена скорость компиляции.

  • А ещё снижено потребление памяти на хранение метаданных плюс обеспечена генерация более компактного кода для архитектуры ARM64. Также отключён сборщик мусора Code (»--yjit-code-gc»), динамически высвобождающий неиспользуемый сгенерированный машинный код, но приводящий к проседанию производительности во время сборки мусора. Появился новый метод RubyVM: YJIT.enable для управления включением YJIT во время работы, без необходимости запуска с определённым параметром командной строки или переменной окружения. Ну и ко всему реализовано расширение статистики, которая выдаётся при указании опции »--yjit-stats». Добавлены режимы профилирования производительности (--yjit-perf) и трассировки (--yjit-trace-exits).

  • Также в основном составе появился парсер Prism. Он добавлен в виде Си-библиотеки libprism, задействованной в интерпретаторе CRuby, и gem-пакета на языке Ruby, предоставляющего общедоступный API для нисходящего рекурсивного разбора кода на языке Ruby, пригодный для использования в рабочих проектах вместо парсера Ripper. Плюс парсера в гибкой обработке ошибок в коде. Для того чтобы включить парсер, нужно воспользоваться опцией «ruby --parser=prism» или переменной окружения RUBYOPT=»--parser=prism». Для разбора кода в программах есть методы Prism.parse (source) для получения AST-представления кода, Prism.parse_comments (source) для выделения комментариев из кода и Prism.parse_success?(source) для проверки наличия ошибок в коде.

  • Ранее для генерации парсеров использовался внешний пакет Bison. Теперь вместо него используется Lrama, который предоставляет реализацию алгоритма LALR на Ruby. Он поддерживает Bison-совместимые определения грамматик (parse.y), используемые в CRuby, реализует расширенные возможности, такие как обработка ошибок и параметризованные правила (?, *, +).

47352b1fc3b50da175eaf2974f9beea6.jpg

  • Добавлен новый JIT-компилятор RJIT. Он написан целиком и полностью на Ruby. Его достоинство — отсутствие необходимости работы с Си-компилятором. RJIT поддерживает только архитектуру x86–64 и Unix-подобные платформы.

  • Появился планировщик потоков «M: N». Он позволяет для сокращения накладных расходов на создание и управление потоками использовать ограниченное число потоков операционной системы для обработки потоков в коде на языке Ruby. По дефолту применяется 8 потоков ОС (можно изменить через переменную окружения RUBY_MAX_CPU). Использование планировщика «M: N» может привести к проблемам с совместимостью с расширениями на языке Си, поэтому он отключён по умолчанию для основного (main) класса Ractor, но включён для неосновных (non-main). Для того чтобы включить планировщик принудительно, нужно выставить переменную окружения RUBY_MN_THREADS=1.

  • Также расширены возможности оболочки интерактивных вычислений IRB (REPL, Read-Eval-Print-Loop). Например, добавлено вычисление IRB (REPL, Read-Eval-Print-Loop). А ещё появилась поддержка многостраничного просмотра вывода команд ls, show_source и show_cmds. Реализована экспериментальная поддержка автоматического дополнения ввода, учитывающая типы данных. Представлены команды для изменения цвета и стиля шрифта.

  • Разработчики решили объявить устаревшим вызов метода «it» без аргументов в блоке без параметров (например,»[1, 2, 3].each { puts it }»).

  • Также в RubyGems и Bundler активировано появление предупреждения в случае указания в «require» gem-пакетов abbrev, base64, bigdecimal, csv, drb, getoptlong, mutex_m, nkf, observer, racc, resolv-replace, rinda и syslog, если они не добавлены в Gemfile или gemspec. В будущих версиях Ruby данные gem-пакеты будут встроены в основной состав.

  • Наконец, обновлены все версии встроенных и входящих в стандартную библиотеку gem-модулей.

© Habrahabr.ru