LINUX.ORG.RU

Ruby 2.4.0

 ,


0

5

25 декабря состоялся первый стабильный релиз ветки Ruby 2.4. В ней представлено много новых возможностей.

  • Улучшения хеш-таблицы (Владимир Макаров). Введены открытая адресация и упорядоченные в порядке добавления массивы. Это обсуждено со многими людьми, в особенности с Юрой Соколовым.
  • Привязка #irb: Старт сессии REPL по аналогии с binding.pry. Вместо логирования переменных множественными вызовами p можно подключить pry через binding.pry для запуска из приложения REPL и выполнения любого Ruby-кода. Теперь в поставку языка включён binding.irb, который позволяет проделать то же самое с irb.
  • Fixnum и Bignum объединены в Integer. Все C-расширения, затрагивающие классы Fixnum или Bignum, нужно поправить.
  • Поддержка соответствий заглавных символов Unicode. String/Symbol#upcase/downcase/swapcase/capitalize(!) теперь работают не только с ASCII.
  • Улучшения производительности. Array#max и Array#min больше не создают временный массив при некоторых условиях. Добавлен Regexp#match?, выполняющий проверку регулярного выражения без создания объекта с обратной ссылкой и изменения $~. Ускорен доступ к переменным экземпляров.

Улучшения отладки:

  • Thread#report_on_exception и Thread.report_on_exception. Ruby игнорирует исключения в потоках, если к ним явно не присоединён другой поток. С report_on_exception = true можно отследить, что поток умер из-за необработанного исключения. Присылайте отзывы, нужно ли включить эту опцию по умолчанию, равно как и report-on-GC, которая сообщает о сборке мусора в неприсоединённом потоке.
  • Отлов тупиков в потоках теперь отображает для потоков трассировку и зависимые потоки.

Другие значимые изменения с версии 2.3:

  • Поддержка OpenSSL 1.1.0 (прекращена поддержка 0.9.7 и более ранних).
  • Из stdlib убраны ext/tk и XMLRPC.

>>> Подробности

>>> Источник

Ответ на: комментарий от Virtuos86

Код этой функции в исходниках Python, поскольку это встроенная функция.

функции с произвольным количеством принимают кортеж. в чём такое уж принципиальное отлие от массива?

NextGenenration ()
Ответ на: комментарий от NextGenenration

Кортеж — контейнер фиксированного размера, immutable object. Сколько в него поместишь элементов при создании, столько памяти он и отъест. Массив динамически изменяемый контейнер, mutable object. Даже если он пустой при создании, виртуальная машина должна учитывать, что он может увеличить размер. Конкретные цифры в кб мне неизвестны, не интересовался. Это есть принципиальное отличие в любом ЯП.

А функции с переменным количеством элементов принимают любой объект, поддерживающий итерацию.

Virtuos86 ★★★★★ ()
Ответ на: комментарий от Virtuos86

Массив динамически изменяемый контейнер, mutable object. Даже если он пустой при создании, виртуальная машина должна учитывать, что он может увеличить размер

в чём проблема? память можно как выделять с запасом так и не выделять. никто же не заставляет.

NextGenenration ()
Ответ на: комментарий от anonymous

По смыслу здесь просится функция, max(1, 3, 0).

Чем это принципиально отличается от [1, 3, 0].max?

Ну с рубистами бесполезно спорить, они не умеют в абстракции, просто тупой молебен на священную корову с переопределенными ногами.

Мощно.

theNamelessOne ★★★★★ ()
Ответ на: комментарий от TDrive

Рубист не понимает зачем нужны два способа

Один. Полиморфный max может в переменное число аргументов и итератор. Причем не надо изобретать god-object для коллекций.

anonymous ()
Ответ на: комментарий от NextGenenration

а теперь код подобной функции в студию. или для 100500 функций для разной длины?

In [1]: from functools import reduce

In [2]: def maxx(*args):
   ...:     return reduce(max, args)
   ...: 

In [3]: maxx(1, 2, 3)
Out[3]: 3

In [4]: maxx(42, 9001)
Out[4]: 9001

In [5]: 
[1] pry(main)> def max(*args)
[1] pry(main)*   args.max  
[1] pry(main)* end  
=> :max
[2] pry(main)> max(1)
=> 1
[3] pry(main)> max(3, 2, 1)
=> 3
[4] pry(main)> max(42, 9001)
theNamelessOne ★★★★★ ()
Ответ на: комментарий от theNamelessOne

Чем это принципиально отличается от [1, 3, 0].max

Тем что не зацикливается на пресловутой чистоте ООП. max выступает как абстрактный оператор. Который может во все что выглядит как итератор и принимает переменное число аргументов, для использования с позиционными параметрами, собственно где и происходит «оптимизация» без ненужного выделения массива. В рубях связаны по рукам и ногам оопностотью, что приводит к костылям. Да, семантика сохранена, но костылем.

anonymous ()
Ответ на: комментарий от anonymous

Один. Полиморфный max может в переменное число аргументов и итератор.

Либо можно определить метод max на всех объектах где он нужен, разница только в том что в твоем случае это не ооп, а в моем случае это ооп.

Причем не надо изобретать god-object для коллекций.

Мне кажется ты не понимаешь что такое god-object. Enumerable в руби это модуль, по сути реализация множественного наследования.

TDrive ★★★★★ ()
Ответ на: комментарий от TDrive

только в том что в твоем случае это не ооп, а в моем случае это ооп.

И нужно блюсти ООП чистоту потому что что? Правильно, потому что руби по-другому не умеют. От того что что-то ООП оно лучше не становиться, такие дела.

Либо можно определить метод max на всех объектах где он нужен

Угу, рубисты никак не могут допетрить, что Enumerable коллекция не обязана содержать сравниваемые объекты, налицо протекающая абстракция. Поэтому то что max находится в Enumerable, просто костылек (иначе бы у вас пуканы рвались от таскания везде реализации) под ООП соусом, а так все чисто, ага.

anonymous ()
Ответ на: комментарий от theNamelessOne

По смыслу здесь просится функция, max(1, 3, 0).

Чем это принципиально отличается от [1, 3, 0].max?

ты просто не постиг божественность конструкции, скорее всего это отзвук: (max 1 3 0)

anonymous ()
Ответ на: комментарий от NextGenenration

Чего ты добиваешься?

хочу показать что [...].max не так уж плохо. и что max(...) не лучше.


Я не утверждаю, что плохо в сравнении с чем-то. Я предполагаю, что плохо само по себе как исключительный случай: запись «[...].max» не создает массив, а творит некую магию, хак. Это даже «сахаром» сложно назвать, это просто синтаксическая неоднозначность.

Virtuos86 ★★★★★ ()
Ответ на: комментарий от Virtuos86

Я предполагаю, что плохо само по себе как исключительный случай: запись «[...].max» не создает массив, а творит некую магию, хак

то ли дело c#: там {} могут быть и для тела метода и для массива и для установки полей при вызове конструктора, using может сокращать путь к классу, а может создавать и уничтожать idisposable объект...

NextGenenration ()
Ответ на: комментарий от anonymous

Тем что не зацикливается на пресловутой чистоте ООП. max выступает как абстрактный оператор.

«Абстрактный оператор» (по факту, toplevel-функция) сам по себе не лучше ООП-метода.

Который может во все что выглядит как итератор

max определён для всего, что включает модуль Enumerable (= «реализует интерфейс»), а Enumerator (= «итератор») включает Enumerable:

[1] pry(main)> ary = Array.new(10) { rand(-5..5) }.each
=> #<Enumerator: ...>
[2] pry(main)> ary.min
=> -4

и принимает переменное число аргументов

А в Ruby с этим проблема? Используя синтаксис literal массивов, мы можем создать массивы разной («переменной») длины:

[3] pry(main)> [1, 3] # массив из двух элементов!
=> [1, 3]
[4] pry(main)> [1, 2, 0] # и из трёх!
=> [1, 2, 0]
[5] pry(main)> 

собственно где и происходит «оптимизация» без ненужного выделения массива

Какая «оптимизация»? *args в Python в любом случае выделит tuple (= «frozen array») для хранения переменного числа аргументов функции.

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

Так и не понял, где ты увидел костыль.

theNamelessOne ★★★★★ ()
Ответ на: комментарий от anonymous

Угу, рубисты никак не могут допетрить, что Enumerable коллекция не обязана содержать сравниваемые объекты

С тем же успехом можно попытаться вызвать метод max у объекта, который его не определил:

In [1]: from random import random                  

In [2]: class boxed(int):
   ...:     def max(self, other):
   ...:         return max(self, other)
   ...:     

In [3]: obj = boxed(42) if random() > 0.5 else "I don't have #max"

In [4]: obj.max(2) # What is about to happen? You guess!

Или передать в функцию max значение не того аргумента:

In [1]: from random import random

In [2]: class nil: pass

In [3]: max(2, nil() if random() > 0.5 else 0)

Но ошибку ты получишь только в рантайме (как и в Ruby).

налицо протекающая абстракция.

Это называется «динамическая типизация».

theNamelessOne ★★★★★ ()
Ответ на: комментарий от Virtuos86

Я предполагаю, что плохо само по себе как исключительный случай: запись «[...].max» не создает массив, а творит некую магию, хак

Это всего лишь детали реализации, о которой програмисту даже не обязательно знать. Многие начинающие C-программисты вообще не подозревают, что при компляции конструкции типа while(false) { } могут быть выкинуты оптимизатором, но ведь в этом нет ничего такого страшного.

theNamelessOne ★★★★★ ()
Ответ на: комментарий от anonymous

И нужно блюсти ООП чистоту потому что что? Правильно, потому что руби по-другому не умеют.

Потому что в руби принята такая парадигма и я не вижу причин её рушить.

От того что что-то ООП оно лучше не становиться, такие дела.

Оно приобретает свои плюсы и минусы как и с любой парадигмой.

Угу, рубисты никак не могут допетрить, что Enumerable коллекция не обязана содержать сравниваемые объекты, налицо протекающая абстракция.

Даже в официальной доке указано

The Enumerable mixin provides collection classes with several traversal and searching methods, and with the ability to sort. The class must provide a method each, which yields successive members of the collection. If Enumerable#max, #min, or #sort is used, the objects in the collection must also implement a meaningful <=> operator, as these methods rely on an ordering between members of the collection.

Можно конечно было бы запилить отдельный модуль для max, min и sort, но это всего 3 метода.

Поэтому то что max находится в Enumerable, просто костылек (иначе бы у вас пуканы рвались от таскания везде реализации) под ООП соусом, а так все чисто, ага.

Как я уже сказал был бы просто еще один модуль с 3 методами. Пукан пока что рвется только у тебя.

TDrive ★★★★★ ()
Ответ на: комментарий от NextGenenration

1) Fixnum и Bignum объединены в Integer. ВСЕ БИБЛИОТЕКИ нужно править и конпилировать. Теперь 70% RubyGems нерабочие!

лучше как в питоне тащить две версии не забывая про кучу хлама который будет лежать ведь зачем переписывать под новую версию если и так работает?

Что значит «куча хлама»??
Для пафосных бездельников, конечно, хлам, а на производстве, в работе - все эти библиотеки трудятся в своих сферах.

И да, Гвидо всё правильно сделал:
питон2.7 - для продакшена,
питон3.Х - для кривляющихся хипстеров.

Вот я например, пользуюсь ruby1.93 и gtk2 и на хипстерские косые-кривые недоделки пересаживаться не собираюсь.

Novator ★★★ ()
Ответ на: комментарий от Novator

Вот я например, пользуюсь ruby1.93 и gtk2 и на хипстерские косые-кривые недоделки пересаживаться не собираюсь.

Так это ж у тебя классический хипстерский винтаж.

Akamanah ★★★★★ ()
Ответ на: комментарий от Anatolik

То, что поддержка завершилась, вас никак не смущает?

Поддержка большинства gems для старого руби наоборот сохранилась. И это огромный плюс для прикладных программистов.

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

Эту ораву хипстеров, как стаю сорок, хватает только на то, чтобы прилететь, погалдеть, всё сломать, всё обосрать и улететь. И пофиг, что инфраструктура разрушена.

Вот за это линукс и не любят.

В винде приснопамятное WinAPI десятилетиями не менялось. Старое API сохраняют, новое рядом добавляют. Была например ShellExecute(), хотят юникод добавить, делают рядом ShellExecuteW() с новыми параметрами, а не ломают первоначальную ShellExecute().

При этом и старый код продолжает работать, и новые функции доступны для прикладных программистов.

В линуксе же постоянно курочат существующее API и делают неработоспособным всё ПО, которое было на это API завязано.

Я не против инноваций, но:
1) должны существовать стабильные master-ветки для продакшена;
2) инновации должны добавляться в testing-ветки;
3) инновации должны годами обкатываться, а не неделями, тем более, когда дело касается всей инфраструктуры языка.

Novator ★★★ ()
Последнее исправление: Novator (всего исправлений: 2)
Ответ на: комментарий от Novator

Для пафосных бездельников, конечно, хлам, а на производстве, в работе - все эти библиотеки трудятся в своих сферах.

так зачем вообще код трогать? работает же! или не понимаешь что обратная совместимость душит возможности по развитию?

Вот я например, пользуюсь ruby1.93 и gtk2 и на хипстерские косые-кривые недоделки пересаживаться не собираюсь.

чем они кривые? не всем нравится сидеть в криокамере. желаю всего наилучшего когда у дистров в которых есть ruby1.93 и gtk2 закончится поддержка.

NextGenenration ()
Ответ на: комментарий от Novator

В винде приснопамятное WinAPI десятилетиями не менялось. Старое API сохраняют, новое рядом добавляют. Была например ShellExecute(), хотят юникод добавить, делают рядом ShellExecuteW() с новыми параметрами, а не ломают первоначальную ShellExecute().

существование дубликатов кода хорошо? нет? сможешь в 10 запустить приложение для 95? как нет? а где же обратная совместимость? или мелкософт просто так так агресивно пересаживает на 10? одна из причин - они устали поддерживать свои старые версии

3) инновации должны годами обкатываться, а не неделями, тем более, когда дело касается всей инфраструктуры языка

для такаих как ты есть джава. емнип там до сих пор «var» не завезли ибо старые умы не способны понять его глубину.

NextGenenration ()
Ответ на: комментарий от Novator

Поддержка большинства gems для старого руби наоборот сохранилась.

Я про поддержку самого MRI(в первую очередь, про обновления безопасности).

А вот для нового руби джемы поломались, больше не конпилируются

Какие именно?

и никто не хочет править сырцы библиотек - это больше всего смущает.

Опять же. Давайте конкретнее. О каких библиотеках речь?

Anatolik ()
Ответ на: комментарий от NextGenenration

Ещё добавлю:
4) все старые вызовы должны по возможности сохраняться, а новый функционал должен добавляться рядом со старым, а не вместо него.

Fixnum и Bignum объединены в Integer. Все C-расширения, затрагивающие классы Fixnum или Bignum, нужно поправить.

Такое свинство в Ruby2.X уже не первый раз происходит. Недавно я скачивал сырцы Ruby-FLTK, пытался сконпилировать, дак ругалось на объявление RARRAY(v) - т.е. эти «погромисты» Си-шные обёртки для базовых классов Ruby меняют как ни в чём не бывало.

или не понимаешь что обратная совместимость душит возможности по развитию?

Откуда такие слабоумные выводы берутся?!
Из какого пальца высасываются??

Обратная совместимость позволяет сохранить все те библиотеки, авторы которых уже давно ими не занимаются, но эти библиотеки продолжают использоваться в продакшене.

Если ПО написано на старом API, если ПО хорошо работает, хорошо отлажено, почему реальные производственники должны гнаться за модой каких-то сопляков? Кто оплатит всю эту свистопляску? Родители этих сопляков? Сомневаюсь. Дураков заниматься бесполезной работой нет.

Ну а ораву хипстеров, я уже говорил, как стаю сорок, хватает только на то, чтобы прилететь, погалдеть, всё сломать, всё обосрать и улететь. И пофиг, что инфраструктура разрушена.

Novator ★★★ ()
Ответ на: комментарий от Anatolik

Я про поддержку самого MRI (в первую очередь, про обновления безопасности).

А я про поддержку старого API.

Пусть язык новый (ruby2.4.0), пусть старый язык (ruby1.9.3) заморожен и не поддерживается. Почему нельзя старые си-шные обёртки сохранить, чтобы старые библиотеки (gems) в новом руби компилировались?

Зачем надо ломать старый вызов RARRAY(v), вместо того чтобы сделать рядом RARRAY2(v)?

Novator ★★★ ()
Ответ на: комментарий от Novator

Обратная совместимость позволяет сохранить все те библиотеки, авторы которых уже давно ими не занимаются, но эти библиотеки продолжают использоваться в продакшене

вот скажи, зачем в продакшене нужны самые последние весрии интерпретатора? ведь по твоей логи и старый прекрасно подойдёт

Если ПО написано на старом API, если ПО хорошо работает, хорошо отлажено, почему реальные производственники должны гнаться за модой каких-то сопляков?

но ведь если сайт который хорошо работает будет требовать ie 6 ты его с радостью поставишь?

Кто оплатит всю эту свистопляску?

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

И пофиг, что инфраструктура разрушена

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

NextGenenration ()
Ответ на: комментарий от Novator

Зачем надо ломать старый вызов RARRAY(v), вместо того чтобы сделать рядом RARRAY2(v)?

зачем? зачем нужен унаследованная хуча хлама? вот допустим что в новой версии у объекта появится новое поле. как такой объект передавать в RARRAY(v)? или ты предлагаешь накопипастить весь код интерептатора чтоб он работал и с тем и другим? да эта копипаста скорее рухнет, чем работать будет.

NextGenenration ()
Ответ на: комментарий от NextGenenration

вот допустим что в новой версии у объекта появится новое поле. как такой объект передавать в RARRAY(v)? или ты предлагаешь накопипастить весь код интерептатора чтоб он работал и с тем и другим?

Именно так и делается у нормальных языкописателей:
все старые вызовы сохраняются, новые добавляются рядом.

Например, если у класса Array появилось новое поле, то нужно доработать си-шную обёртку так, чтобы вызов RARRAY(v) не крашился при компиляции уже написанных библиотек.

Да, теперь надо поддерживать RARRAY(v) и RARRAY2(v), но по-другому инфраструктуру языка не сохранить. Да, нужно вкалывать, да, нужно отвечать за любое изменение, причём отвечать работоспособным кодом, а не болтовнёй в форумах.

Но (вопрос риторический) способны ли на ответственное поведение новые поколения пафосных хипстеров-«погроммистов», никогда не сталкивавшихся с производством?

Novator ★★★ ()
Ответ на: комментарий от Novator

Например, если у класса Array появилось новое поле, то нужно доработать си-шную обёртку так, чтобы вызов RARRAY(v) не крашился при компиляции уже написанных библиотек.

и сколько процентов от кода у тебя будет составлять эти обёртки? как быстро ты запутаешься во очередной копипасте очередного метода? каково будет программисту если внезапно выяснится что данный объект не поддерживает данный метод, ведь этот объект версии 0.9 а метод появился в 2.5?

Да, теперь надо поддерживать RARRAY(v) и RARRAY2(v)

на самом деле гораздо больше кода чем 2 метода. всё что подверглось изменению будет продублированно. и это в каждой новой версии

Да, нужно вкалывать, да, нужно отвечать за любое изменение, причём отвечать работоспособным кодом, а не болтовнёй в форумах

мазохист? вот обновился a теперь нужно продублировать весь код для a на версии 1 и 2. в следующей весрии обновился класс b работающий с a. сколько весрий надо? четыре: b1(a1) b2(a1) b2(a1) b2(a2). допустим вышла ещё одна версия b. Сколько сейчас? b1(a1) b2(a1) b3(a1) b2(a1) b2(a2) b3(a2). а ведь это всего лишь 3 маленьких изменения

Но (вопрос риторический) способны ли на ответственное поведение новые поколения пафосных хипстеров-«погроммистов», никогда не сталкивавшихся с производством?

а что там на производстве? прям всё идеально? да в производстве куча проблем на которые никто не смотрит ведь работает не трожь

NextGenenration ()
Ответ на: комментарий от Novator

Недавно я скачивал сырцы Ruby-FLTK, пытался сконпилировать

Если открытой библиотеки для Ruby нет на https://rubygems.org, то она не для продакшена.

Там последний коммит — в 2007, а разработка активно велась — в 2002.

Почему нельзя старые си-шные обёртки сохранить, чтобы старые библиотеки (gems) в новом руби компилировались?

Чтобы было проще поддерживать и развивать язык. Особенно, когда то, что вы называете «си-шными обёртками» — не публичный API.

Зачем надо ломать старый вызов RARRAY(v), вместо того чтобы сделать рядом RARRAY2(v)?

Это не вызов, а макрос. В расширениях, по возможности, его использования следует избегать. Смотрите подробнее здесь:

The VALUE of the type which has the corresponding structure can be cast to retrieve the pointer to the struct. The casting macro will be of the form RXXXX for each data type; for instance, RARRAY(obj). See “ruby.h”. However, we do not recommend to access RXXXX data directly because these data structure is complex. Use corresponding rb_xxx() functions to access internal struct. For example, to access an entry of array, use rb_ary_entry(ary, offset) and rb_ary_store(ary, offset, obj).

Don’t touch pointers directly

In MRI (include/ruby/ruby.h), some macros to acquire pointers to the internal data structures are supported such as RARRAY_PTR(), RSTRUCT_PTR() and so on.

DO NOT USE THESE MACROS and instead use the corresponding C-APIs such as rb_ary_aref(), rb_ary_store() and so on.

Anatolik ()
Ответ на: комментарий от Novator

Кто будет 70% библиотек переписывать для продакшена, «ненужнисты»?

Они поломаны только в вашем воображении. Вы ведь 70% взяли с потолка, не так ли?

Что у вас не работает кроме Ruby-FLTK?

Anatolik ()
Ответ на: комментарий от Novator

Если вы хотите, чтобы на ваши вопросы отвечали, и относились к вам с уважением, то вам следует научиться отвечать на чужие.

На те, которые я задал здесь, вы не ответили.

Anatolik ()
Последнее исправление: Anatolik (всего исправлений: 1)
Ответ на: комментарий от Novator

Уже очевидно, что никто не будет.

Сопливые ruby-хипстеры сломали Си-шные обёртки для своей пускали рельсов. Таким образом сделали неработоспособными 70% библиотек.

Следовательно 50% прикладного ПО, написанного на Ruby, лишившись библиотек, перестанет функционировать.

В то время как твёрдотелый Гвидо объявляет поддержку Python2.7 до 2020 года, мягкотелый Юкихиро молча созерцает, как ruby-сопляки объявляют о прекращении поддержки Ruby1.9.

Потом анонимусы удивляются, почему на питоне написано столько приложений (в том числе десктопных), а руби остаётся пускалкой для рельсов.

Я вот тоже, погляжу-погляжу ещё немного на это свинство, да и перейду на питон. К тому же питон я тоже знаю.

Мне конечно чисто эстетически код на руби больше нравится, и как базовые классы реализованы нравится, и как основные библиотеки организованы.

Но когда у тебя каждый релиз какая-нибудь либа отваливается, либо ты обнаруживаешь, что новые версии интерпретаторов под windows доступны только для x64, то уже становится плевать как-то на «философию руби» и «ruby way» - своя рубашка ближе к телу, мне ехать, а не шашечки, мне надо чтоб язык был удобен и поддерживал меня, а не ставил палки в колеса.

Мои проблемы, как прикладного программиста, и проблемы пользователей моих программ для меня важнее, чем идеологическая слизь в голове прыщавых хипстеров и японского слизняка.

Novator ★★★ ()