LINUX.ORG.RU

Релиз Ruby 2.1

 


5

9

Прекрасный новогодний подарок преподнес Matz всем любителям и профессионалам программирования на языке Ruby — релиз Ruby 2.1. В целом новый выпуск языка и среды исполнения написанного на нем кода продолжает эволюционное развитие Ruby и практически не вносит кардинальных или ломающих изменений. Кроме того, что стандартный интерпретатор стал работать быстрее, заявлены следующие отличительные особенности Ruby 2.1:

  • Кэширование названий методов. Теперь когда интерпретатор встречает название какого-то метода объекта, он производит поиск этого метода, после чего сохраняет указатель на него в байткоде. Если у вас есть код, в котором для объектов одного и того же типа часто вызывается один и тот же метод, работа этого участка программы будет ускорена. Для проверки корректности сохраненного значения в кэше MRI использует внутренние счетчики потенциально опасных в плане инвалидации кэшированного метода действий.
  • Поддержка профайлинга кода на уровне MRI. Вы можете измерять производительность вашего кода и отслеживать работу сборщика мусора (благодаря подписке на события запуска/останова сборщика мусора и создания/удаления объектов).
  • Обновленный сборщик мусора RGenGC (с поколениями). Более подробно с ним можно ознакомиться в захватывающей презентации [pdf] с RubyConf.
  • Добавлены суффиксы i и r для записи комплексных чисел.
  • Определение функции (def) теперь возвращает символ ее названия вместо nil.
  • Работа над неоднозначностью объявления refinements, то есть расширения модуля или класса в пределах одного локального файла. Подробнее [pdf].
  • Наконец-то Array#to_h — создание хэша из массива.
  • Сокращение записи «замороженных» строк (str = «mystring"f).
  • Для ускорения операций над очень большими числами используется GMP (The GNU Multiple Precision Arithmetic Library).
  • Обновлены стандартные библиотеки BigDecimal, JSON, NKF, Rake, RubyGems и RDoc.
  • Удалена поддержка из коробки curses (гем curses теперь при необходимости надо установить отдельно).
  • А также многое другое! Подробный список изменений прилагается.

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

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

★★★★★

Проверено: Shaman007 ()
Последнее исправление: ymn (всего исправлений: 1)
Ответ на: комментарий от special-k

Ты правда думаешь, что определение __iter__ в объекте (чтобы заработал join) все распутывает..

Ыыыыы... я не предлагал определять __iter__ для того, чтобы заработал join, что за идиотская идея. Надо тебе склеивать строковые представления объектов - ".join([str(o) for o in whatever])

tailgunner ★★★★★
()
Ответ на: комментарий от special-k

Может переселялись?

Переселялись это когда плавно и аккуратно. А когда «бросайте всё здесь и езжайте нахуй отсюда вон на том поезде», это депортировались.

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

Ок, насильно переселялись - так пойдет?

Моя википедия говорит, что это и есть департация.

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

адо тебе склеивать строковые представления объектов - ".join([str(o) for o in whatever])

правильнее будет ".join(map(str, whatever))

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

Я не Гвидо, история неизвестна. Вместо абстрактной iterable и многих прочих вещей в Пайтоне есть соглашения. Об именовании приватных полей классов, об именовании пакетов/модулей/классов/переменных etc. Некоторые носят чисто умозримый характер, некоторые заложены в язык.

Так, итератором называется объект, который имеет метод «next»; также неплохо, если по исчерпании этот метод будет выбрасывать исключение StopIteration. Цикл for и map/filter/reduce умеют автоматически обрабатывать это исключение, считая его окончанием итерации — тоже соглашение. Это вместо iterable. Нет, стройная иерархия базовых типов это гуд, кто спорит.

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

неплохо будет и ".join(str(o) for o in whatever). как минимум, lazy

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

whatever.join

Не читал ваш всю вашу увлекательную дискуссию на счёт правильного расположения join'а, мб что скажу ниже уже писали.

join() должен быть у строкового объекта по следующим причинам:

1. Соблюдение типизации и предсказуемость результата. Нельзя склеивать гетерогенный набор объектов (~объекты разных типов), т.е. не понятно что должно быть в таком случае на выходе. join(), как метод у экземпляра строки или класса (~ статический метод), проверяет чтобы было всё как нужно.

2. Особенности реализации. Какие-то объекты можно склеивать очень эффективно, какие-то нет. join(), как часть str, знает как можно эффективно это сделать. Для питона это особенно актуально, т.к. строки немутабельны.

3. join() не имеет общей семантики и общего смысла среди всех одноимённых операций и для большей части объектов такой операции вообще не существует. Потому логичнее реализовывать его как метод экземпляра или статический метод класса с описанием чего оно делает.

upd: А семантика whatever.join() называется reduce()

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

Нифига. Официально рекомендуется именно list comprehension.

этого точно делать не стоит, по крайней мере в твоём варианте, т.к. сначала будет сделан весь список. Вариант с map() отдаст итератор в py3

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

сначала будет сделан весь список

Ну и что? Для целей иллюстрации вполне подойдет, и в 99.99% реальных случаев замена на map ничего не даст (кроме некоторого замедления).

Вариант с map() отдаст итератор в py3

Ну что за полумеры, напиши уже ленивый join.

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

join() должен быть у строкового объекта по следующим причинам:

1. Соблюдение типизации и предсказуемость результата. Нельзя склеивать гетерогенный набор объектов (~объекты разных типов), т.е. не понятно что должно быть в таком случае на выходе. join(), как метод у экземпляра строки или класса (~ статический метод), проверяет чтобы было всё как нужно.

*facepalm*

Он и как метод дроби мог бы делать тоже самое. Не аргумент.

2. Особенности реализации. Какие-то объекты можно склеивать очень эффективно, какие-то нет. join(), как часть str, знает как можно эффективно это сделать. Для питона это особенно актуально, т.к. строки немутабельны.

*facepalm*

Вменяемый программист никогда не запихнёт обработку с «особеннастями реализации» в один общий класс. «особенности реализации» должны быть в своих собственных классах. Это вообще аргумент не за, а против.

3. join() не имеет общей семантики и общего смысла среди всех одноимённых операций и для большей части объектов такой операции вообще не существует. Потому логичнее реализовывать его как метод экземпляра или статический метод класса с описанием чего оно делает.

Я ннп.

join() логично реализовывать как метод в классе, для которого join имеет смысл, а не в абсолютно левом классе string. Не аргумент.

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

Он и как метод дроби мог бы делать тоже самое. Не аргумент.

т.е. метод join() у дроби мог бы склеивать строки? Молодец, продолжай дальше принимать упорин.

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

О чём я выше и написал. join() у str это не общий метод и класс для всех на свете join'ов, а конкретный, только для строк. Но join() у whatever как раз общий, который должен будет уметь работать с особенностями всех типов объектов.

Я ннп.

есть join() для строк. А ещё есть для пулов процессов, самих процессов и т.п. Всё эти операции делают разные вещи, но называются одинаково. Что должен делать [process1, ... ,process2].join()?

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

Я ему уже написал, ноль внимания.

я уже прочитал, не нужно переживать

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

О чём я выше и написал. join() у str это не общий метод и класс для всех на свете join'ов, а конкретный, только для строк.

Выше я не читал, но мне виртуоз говорит, что join не только для строк Релиз Ruby 2.1 (комментарий)

На остальное не отвечал, ибо недопонимание похоже отсюда.

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

Выше я не читал, но мне виртуоз говорит, что join не только для строк Релиз Ruby 2.1 (комментарий)

Который ".join() только для строк. Там же написано

В Пайтоне любой объект, способный быть итератором<...>, который будет выдавать строки при каждой итерации может быть склеен при помощи <...>

Cписок из строк сам по себе есть объект итератор которого будет возвращать строки. Потому для ".join() всё равно что будет дано на входе - список из строк или итератор их выплёвывающий.

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

join(), соответственно, хочет получить на вход объект, который можно итерировать. Не важно будет это список или любой другой контейнер или объект маскирующийся под него. Главное чтобы через итерирование можно было получить набор строк для склеивания.

Можно даже сделать так

>>> ''.join(['a', 'b'])
'ab'
>>> ''.join({'a' : '1' , 'b': '2'})
'ab'
>>> ''.join({'a' : '1' , 'b': '2'}.values())
'12'

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

Нет...

... основная проблема С не от:

Выделять память - отдельно, освобождать память - отдельно, что-то делать с памятью - отдельно.

А от того, что «single responsibility principle» к С пытаются применить. Память не есть объект. И никогда им не была. Она может быть объектом только в воспалённом мозгу плюсовца.

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

Ну и что? Для целей иллюстрации вполне подойдет, и в 99.99% реальных случаев замена на map ничего не даст (кроме некоторого замедления).

Всё таки решил проверить про замедление. Вариант с map быстрее более чем в два раза на py2 и в полтора на py3 на небольших списках. Разница, похоже, только из-за юникодовых строк.

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

Вариант с map быстрее более чем в два раза на py2 и в полтора на py3 на небольших списках

Я мерял на средних numpy-массивах.

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

Я мерял на средних numpy-массивах.

Значит, посчитал погрешность измерений за «некоторое замедление». Превращение numpy.int64 в str почти в сотню раз медленнее чем время работы самого итератора.

mashina ★★★★★
()
Ответ на: комментарий от special-k

Питонщеги спорят про join в руби-трэде.. это так.. мило ^_^

И показательно. Такой вот популярный Руби - в топиках о нем питонщики спорят %)

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

ar[0..0] - очевидно, вернуть массив элементов с нулевого по нулевой.

ar[1..1] - то же самое.

Дальнейшее неочевидно, но описано в документации: http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-slice

ar[2..2]

For start and range cases the starting index is just before an element. Additionally, an empty array is returned when the starting index for an element range is at the end of the array.

В этом случае индекс 2 - как раз конец массива, 2 == ar.length.

ar[3..3]

Returns nil if the index (or starting index) are out of range.

Здесь индекс уже за пределами массива, ибо 3 > ar.length

Почему выбрано именно такое поведение? Скорее всего, по тем же соображениям, что и ar[100500] == nil, для сокращения и упрощения кода.

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

У тебя и кед не существует, хватит завидовать :}

Deleted
()
Ответ на: комментарий от special-k

Питонщики пишут правильно, а рубисты - красиво

выглядит и читается как противопоставление, т.е. у рубистов код красивый, но неправильный ☺

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

В этом случае индекс 2 - как раз конец массива, 2 == ar.length.

Для массива длинной 2 элемента последний индекс равен 1.

Здесь индекс уже за пределами массива, ибо 3 > ar.length

Индекс 2 тоже за пределами массива потому что последний индекс равен 1.
Такое поведение потому что руби писал неадекватный японец.

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

Для массива длинной 2 элемента последний индекс равен 1.

Что такое «последний индекс»? Индекс последнего элемента - да, 1. И? Прочти сообщение внимательно, об индексе последнего элемента там речи не шло.

Индекс 2 тоже за пределами массива потому что последний индекс равен 1.

Ещё раз: если стартовый индекс меньше длины массива, вернуть элементы, начиная с него; если стартовый индекс равен длине массива, вернуть пустой массив; если стартовый индекс больше длины массива, вернуть nil.

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

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

Анонимус просто не будет юзать кучу подпорок под названием Раби.

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

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

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

Выглядит как попытка придумать логичное объяснение там где логики нет...

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

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

deadlock
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.