Опубликован язык программирования Ruby 3.3

Состоялся релиз Ruby 3.3.0, динамического объектно-ориентированного языка программирования, отличающегося высокой эффективностью разработки программ и вобравшего в себя лучшие черты Perl, Java, Python, Smalltalk, Eiffel, Ada и Lisp. Код проекта распространяется под лицензиями BSD (“2-clause BSDL”) и “Ruby”, которая ссылается на последний вариант лицензии GPL и полностью совместима с GPLv3.

Основные улучшения:

  • В основной состав включён парсер Prism, реализованный в форме Си-библиотеки libprism, задействованной в интерпретаторе CRuby, и gem-пакета на языке Ruby, предоставляющем общедоступный API для нисходящего рекурсивного разбора кода на языке Ruby, пригодный для использования в рабочих проектах вместо парсера Ripper. Из достоинств Prism отмечается хорошая переносимость и гибкая обработка ошибок в коде. Для включения нового парсера можно использовать опцию “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, и реализующий расширенные возможности, такие как обработка ошибок и параметризированные правила (?, *, +).
  • Проведена значительная оптимизация производительности JIT-компилятора YJIT, развиваемого разработчиками платформы электронной коммерции Shopify в рамках инициативы по увеличению производительности Ruby-программ, использующих фреймворк Rails и вызывающих очень много методов. В отличие от ранее используемого JIT-компилятора MJIT новый YJIT применяет версионирование базовых блоков (LBBV – Lazy Basic Block Versioning) вместо обработки методов целиком и реализован в форме интегрированного JIT-компилятора, написанного на языке Rust. Благодаря LBBV, JIT вначале компилирует только начало метода, а оставшуюся часть компилирует через некоторое время, после того как в процессе выполнения будет определены типы используемых переменных и аргументов.

    При тестировании выполнения эмулятора Optcarrot производительность при использовании YJIT более чем в три раза превышает выполнение при помощи интерпретатора. В новой версии обеспечено выделение регистров для стековых операций виртуальной машины, расширен спектр компилируемых вызовов с необязательными аргументами, реализовано 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).

  • Предложен новый JIT-компилятор RJIT, написанный целиком на языке Ruby и заменяющий MJIT, но в отличие от последнего при использовании не требующий Си-компилятора. RJIT поддерживает только архитектуру x86-64 и Unix-подобные платформы.
  • Добавлен планировщик потоков “M:N”, позволяющий для сокращения накладных расходов на создание и управление потоками использовать N потоков операционной системы для обработки M потоков в коде на языке Ruby. По умолчанию используется 8 потоков ОС (можно изменить через переменную окружения RUBY_MAX_CPU). Применение планировщика “M:N” может привести к проблемам с совместимостью с расширениями на языке Си, поэтому он отключён по умолчанию для основного класса Ractor, но включён для неосновных (non-main). Для принудительного включения планировщика “M:N” следует выставить переменную окружения RUBY_MN_THREADS=1.
  • Расширены возможности оболочки интерактивных вычислений IRB(REPL, Read-Eval-Print-Loop). Добавлен режим отладки irb:rdbg, эквивалентный по своим возможностям pry-byebug. Добавлен поддержка многостраничного просмотра для команд 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-модулей.
Release. Ссылка here.