Источник изображения

Хорошие новости для разработчиков — вышел Ruby 3.0.0, новый релиз динамического объектно-ориентированного языка программирования. По словам его поклонников, в новую версию вошло лучшее от Perl, Java, Python, Smalltalk, Eiffel, Ada и Lisp.

Новая версия Ruby — восьмой значительный выпуск, который получил множество обновлений и улучшений. К слову, над третьей версией разработчики трудились около пяти лет. Ее особенности — высокая производительность, параллелизм и типизация.

Кстати, те же пять лет назад автор языка Юкихиро Мацумото (Yukihiro Matsumoto) предложил концепцию Ruby 3x3. Она подразумевает, что выпуск Ruby 3.0 станет возможным после того, как удастся добиться трехкратного прироста производительности по сравнению с версией 2.0. В последнем релизе этого удалось добиться благодаря усовершенствованию поддержки JIT-компиляции.

Что нового?


  • Разработчики добавили большое количество улучшений в MJIT. Например, увеличена производительность при таких рабочих нагрузках, как игры (тест Optcarrot), AI (тест Rubykon). Аналогичным образом увеличена производительность для любых приложений, где большая часть времени тратится на многократный вызов нескольких методов. Кроме того, снижен и размер кода, который генерируется компилятором. Речь о JIT-компиляторе, который, правда, еще не готов для оптимизации приложений, использующих фреймворк Rails. В этом случае охватывается большое количество методов, что приводит к неэффективной работе кэша i-cache.


  • Появился инструментарий для аннотации типов RBS, поддерживающий большинство популярных шаблонов в программах на языке Ruby. Аннотации RBS дают возможность выполнять статический анализ кода без явного определения типов. Также предоставляются средства для описания определений классов и модулей: методы, определенные в классе, переменные экземпляра и их типы, а также иерархия наследования или подмешивания модулей. Плюс ко всему, появился экспериментальный анализатор типов TypeProf, который читает код, анализирует использование методов и генерирует прототип аннотаций типов в формате RBS.

   module ChatApp
     VERSION: String
     class Channel
      attr_reader name: String
       attr_reader messages: Array[Message]
       attr_reader users: Array[User | Bot]  # `|` means union types, `User` or `Bot`.
       def initialize: (String) -> void
       def post: (String, from: User | Bot) -> Message  # Method overloading is supported.
            | (File, from: User | Bot) -> Message
     end
   end

  • Добавлена экспериментальная поддержка модели акторов Ractor. Она предоставляет абстракцию, которая разработана для обеспечения потокобезопасного параллельного выполнения программы. Сообщается, что поддерживается создание нескольких ракторов, а также их параллельный запуск. Между собой ракторы взаимодействуют путем передачи сообщений.

   require 'prime'
   # n.prime? with sent integers in r1, r2 run in parallel
   r1, r2 = *(1..2).map do
    Ractor.new do
      n = Ractor.recv
       n.prime?
     end
   end
   # send parameters
   r1.send 2**61 - 1
   r2.send 2**61 + 15
   # wait for the results of expr1, expr2
   p r1.take #=> true
   p r2.take #=> true

  • Появился планировщик легковесных fiber-потоков Fiber#scheduler, поддерживающий перехват блокирующих операций для обеспечения легкого параллелизма, не требующего изменения существующего кода. Вот классы и методы, которые поддерживаются:

— Mutex#lock, Mutex#unlock, Mutex#sleep
— ConditionVariable#wait
— Queue#pop, SizedQueue#push
— Thread#join
— Kernel#sleep
— Process.wait
— IO#wait, IO#read, IO#write и связанные с ними методы

require 'async'
   require 'net/http'
   require 'uri'
   Async do
     ["ruby", "python", "c"].each do |topic|
       Async do
         Net::HTTP.get(URI "https://www.google.com/search?q=#{topic}")
       end
     end 
   end

  • Подверглись переработке однострочники сопоставления с образцом «Добавление оператора — значение-переменная», что используется для правостороннего присваивания значений.

   0 => a
   p a #=> 0
   {b: 0, c: 1} => {b:}
   p b #=> 0

Кроме того, изменено и поведение «in», теперь он возвращает true или false.
   # version 3.0
   0 in 1 #=> false
   # version 2.7
   0 in 1 #=> raise NoMatchingPatternError

Добавлен экспериментальный шаблон для поиска значений:

   case ["a", 1, "b", "c", 2, "d", "e", "f", 3]
   in [*pre, String => x, String => y, *post]
     p pre  #=> ["a", 1]
     p x    #=> "b"
     p y    #=> "c"
     p post #=> [2, "d", "e", "f", 3]
   end

  • Добавлен метод Hash#except.

   h = { a: 1, b: 2, c: 3 }
   p h.except(:a) #=> {:b=>2, :c=>3}

  • Появилась поддержка однострочного определения метода без использования ключевого слова «end».

   def square(x) = x * x

  • Также разработчики добавили экспериментальный C-API для обмена областями памяти между библиотеками-расширениями и предоставления метаданных о содержимом памяти.
  • Увеличена производительность интерактивного интерпретатора IRB. Сообщается, что вставка больших участков кода производится в 53 (!) раза быстрее, чем в Ruby 2.7.
  • Обновлены важные gem-модули, являющиеся частью stdlib.