...

понедельник, 30 сентября 2013 г.

[Из песочницы] Чего нам ждать от Ruby 2.1?

Несколько дней назад Константин Хаасе, один из ключевых людей в сообществе Ruby, опубликовал запись в своём блоге, посвящённую анонсу предварительной версии Ruby 2.1. Изменений между версиями 2.0 и 2.1 накопилось достаточно, чтобы вчитаться в его изложение, и лучше — на русском языке.



NB: разумеется, Ruby 2.1 содержит все замечательные возможности предыдущей версии — 2.0. Изменения предыдущих версий упоминаться не будут.

Механизм уточнений




Известно, что в Ruby 2.0 введён механим уточнений. Реализация данного механизма оказалась достаточно противоречивой, поэтому в версии 2.0 его функциональность была несколько ограничена и помечена как экспериментальная.

Стоит напомнить, что уточнения позволяют применять манки патчи в рамках единственного Ruby-файла:



module Foo
refine String do
def foo
self + "foo"
end
end
end

using Foo
puts "bar".foo




За пределами данного файла экземпляры класса String не будут отвечать на метод foo.



В новой версии Ruby уточнения не будут являться экспериментальной возможностью. Более того, их можно будет применять не только к области видимости верхнего уровня, но и к отдельным модулям.

module Foo
refine String do
def foo
self + "foo"
end
end
end

module Bar
using Foo
puts "bar".foo
end




Важно иметь в виду, что чрезмерное увлечение уточнениями может привести к написанию достаточно запутанного кода. Разработчики некоторых реализаций Ruby уже заявили, что могут отказаться поддерживать уточнения.

Десятичные литералы




При работе с Ruby можно заметить, что значения с плавающей запятой ведут себя не лучшим образом, когда над ними выполняются вычисления, привычные по работе с десятичными дробями:

irb(main):001:0> 0.1 * 3
=> 0.30000000000000004




Подобное поведение приводит к тому, что большое количество Ruby-разработчиков начинает использовать целые числа, имитируя заданное количество знаков после запятой при представлении результата. Безусловно, такой способ работает хорошо при строго заданном количестве знаков после запятой. В противном случае приходится использовать рациональные дроби — это не очень плохо, но язык не обладает достаточно удобным синтаксисом для работы с ними.

Новая версия Ruby представляет суффикс r для описания десятичных и рациональных дробей:



irb(main):001:0> 0.1r
=> (1/10)
irb(main):002:0> 0.1r * 3
=> (3/10)




Замороженные строковые литералы




Если в коде содержится объявление строкового литерала, то каждый раз при исполнении содержащей его строки кода Ruby создаёт новый объект класса String. Это обусловлено мутабельностью строк. В таких случаях символы ведут себя гораздо эффективнее, так как инициализируются всего один раз. Тем не менее, для сравнения символа со строкой нужно провести преобразование строки в символ или символа в строку. Выполнение таких преобразований — рискованная операция, открывающую потенциальную возможность для DoS-атаки, так как символы не освобождаются при сборке мусора, а любое преобразование символа в строку создаёт новую строку.

Единственный способ уберечь себя от негативных последствий в данном случае — хранить и использоваться строку в виде константы:



class Foo
BAR = "bar"

def bar?(input)
input == BAR
end
end




Часто, чтобы избавиться от мутабельности, выполняют заморозку строки. Заморозка объекта предотвращает его изменение со стороны кода на Ruby, однако не даёт никаких прибавок к производительности:

class Foo
BAR = "bar".freeze

def bar?(input)
input == BAR
end
end




Это выглядит достаточно нелепо и громоздко. К счастью, Ruby 2.1 предлагает новый синтаксис для решения данной задачи:

class Foo
def bar?(input)
input == "bar"f
end
end




В приведённом коде будет создан замороженный объект класса String, и где бы он не использовался — он будет инициализирован всего один раз.

Не исключено, что такой синтаксис может показаться странным. Тот же самый фрагмент кода можно переписать эквивалентно:



class Foo
def bar?(input)
input == %q{bar}f
end
end




Вообще, вопрос применения суффикса f к массивам и хэшам остаётся открытым.

Обязательные ключевые аргументы




Почему-то в анонсе Ruby 2.0 не были упомянуты обязательные ключевые аргументы. Итак, Ruby 2.0 представляет обязательные ключевые аргументы:

def foo(a: 10)
puts a
end

foo(a: 20) # 20
foo # 10




При таком подходе к объявлению методов приходится указывать значения аргументов по-умолчанию. Это не всегда возможно, поэтому Ruby 2.1 позволяет задать обязательные ключевые аргументы:

def foo(a:)
puts a
end

foo(a: 20) # 20
foo # ArgumentError: missing keyword: a




Объявление метода возвращает имя метода




В предыдущих версиях Ruby объявление метода при помощи def возвращало nil.

def foo() end # => nil




Теперь это поведение изменилось и имя метода возвращается как символ:

def foo() end # => :foo




Это полезно при метапрограммировании и выполнении подобных трюков. Например, все ли знают, что метод private может принимать аргументы?

# приватным будет только метод foo
class Foo
def foo
end

private :foo

# метод bar останется незатронутым
def bar
end
end




Теперь, когда def возвращает имя объявленного метода, можно легко делать методы приватными:

# приватными будут только методы foo и bar
class Foo
private def foo
end

private \
def bar
end

def baz
end
end




Удаление лишних байт из строк




Теперь Ruby имеет удобный метод для удаление лишних байт из строк:

some_string.scrub("")




Раньше было сложно добиться одинакового поведения такого метода для всех существующих реализаций Ruby, поэтому также доступна библиотека для этого.

StringScanner поддерживает именованные захваты




Многим нравится класс StringScanner из стандартной библиотеки языка. В частности, он используется в Rails для разбора шаблонов маршрутов. То же самое будет делать Sinatra 2.0.

В версии 1.9 была добавлена поддержка именованных захватов, однако StringScanner их не поддерживал:



require 'strscan'
s = StringScanner.new("foo")
s.scan(/(?<bar>.*)/)
puts s[:bar]




При запуске данного кода на Ruby 2.0 будет получено исключение:

TypeError: no implicit conversion of Symbol into Integer




Зато при запуске на Ruby 2.1:

foo




Работа с сетевыми интерфейсами




Теперь можно получить доступ к сетевыми интерфейсам при помощи метода Socket.getifaddrs:

require 'socket'

Socket.getifaddrs.each do |i|
puts "#{i.name}: #{i.addr.ip_address}" if i.addr.ip?
end




Пример вывода такой программы:

lo0: fe80::1%lo0
lo0: 127.0.0.1
lo0: ::1
en0: fe80::1240:f3ff:fe7e:594e%en0
en0: 192.168.178.30
en2: fe80::3e07:54ff:fe6f:147a%en2




Быстрая работа с числами для вычислительных задач




Ruby 2.1 ведёт себя быстрее при работе с большими числами благодаря использованию 128-битных целых чисел в качестве внутреннего представления объектов класса Bignum. Более того, применение GNU Multiple Precision Arithmetic Library даёт дополнительный прирост к производительности.

Изменения в виртуальной машине




Теперь виртуальная машина Ruby наряду с использованием глобального кэша методов выполняет кэширование по месту вызова функции. Про это есть отдельные слайды.

RGenGC




Новая версия Ruby частично оснащена сборщиком мусора на основе поколений. Благодаря этому сборка мусора будет происходить быстрее. До этого использовался консервативный сборщик мусора, работающий по схеме «stop the world — mark — sweep».

На самом деле, старый сборщик никуда не исчез. Такие вещи сложно менять из-за особенностей внутреннего и внешнего программного интерфейса Ruby для языка Си.


Тем не менее, виртуальная машина Ruby 2.1 выполняет классификацию объектов на светлые и тёмные. В зависимости от присвоенного класса определяется поведение сборщика мусора. Имеются операции, которые делают светлый объект тёмным. Например, работа с ним из расширения на языке Си. Такие объекты, как открытые файлы, являются тёмными изначально.


Новый сборщик мусора работает только со светлыми объектами.


Обновление RubyGems




RubyGems получили обновление до версии 2.2.0, которая приносит несколько незначительных усовершенствований.

И это лишь предварительная версия!




Не стоит забывать, что недавний релиз является лишь предварительной версией, и всё вышеописанное может измениться.

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends:



Комментариев нет:

Отправить комментарий