Последнее в категории Версии Perl

Часть I
История и статистика

Perl 5.10 увидел свет в 20 день рождения языка — 18 декабря 2007 года. Уже прошло более двух лет, и за это время успели появиться девелоперские версии 5.11.0, 5.11.1, 5.11.2, 5.11.3 и 5.11.4, и вот-вот появится версия 5.12, предназначенная для использования в реальных приложениях.

Perl 5.10 представил много нововведений, и сегодня интересно посмотреть, как часто они используются авторами модулей CPAN — модулей, появившихся после релиза 5.10, либо обновленных с того времени.

На CPAN сейчас хранится около 80 000 модулей в 20 000 дистрибутивах, список авторов содержит около 8000 имен. Как часто здесь используются фичи Perl 5.10?

Ответ: новые фичи встречаются в двух сотнях модулей, созданных сотней авторов.


Часть II
Фичи Perl 5.10

Кратко о том, что появилось в Perl 5.10.

— Встроенная функция say, которая работает аналогично print, но добавляет перевод строки.

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

$a ~~ /\d/

$a ~~ @list

@list ~~ %hash

— Составной оператор выбора под условным названием switch. С помощью новых ключевых слов given, when и default возможно создать условную конструкцию, аналогичную switch/case в C и других языках. Важное отличие в том, что внутри given происходит не простое сравнение, а сопоставление (или смартматчинг).

given($x) {
    when(/a/) {...}
    when('b') {...}
    default   {...}
}

— Модификатор state позволяет создавать лексические переменные, сохраняющие значение между вызовами подпрограммы. Использование state похоже на объявление автоматической переменной со словом static в C.

sub counter {
    state $c = 0;
    return ++$c;
}

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

(?<name>)
\K
\R
%+
%-
\g<name>

— Бинарный оператор defined-or (//). Возвращает первый из аргументов, который содержит определенное (не undef) значение. Может использоваться и в варианте с присвоением.

Следующие два примера иллюстрируют логику, которая часто прослеживается в сообщениях о вакансиях.

$city = $arg // 'Moscow';

$vacancy{city} //= 'Moscow';


Продолжение будет.

На седьмом голландском Perl-воркшопе, который пройдет в Арнхеме 5 марта, подобралась завораживающая коллекция докладов о разных версиях Perl (перечислены в порядке возрастания версии :-)

Perl 5.10 в 2010-м

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

Моя презентация на «Перлбурге».

Презентация в пяти частях, основное содержание — о том, как и зачем используют возможности 5.10 в новых модулях на CPAN и мои примеры вариантов применения, которые я показывал на onperl.ru.


View more presentations from andy.sh.

На спане есть некоторое число модулей, которые используют новые возможности версии Perl 5.10.

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

use 5.010000;
use 5.01001;
use 5.0100;
use 5.010;
use 5.010_000;
use 5.10.0;
use v5.10.0;
use v5.10;
use feature ':5.10';

О том, что еще творится на спане, я расскажу на Перлбурге :-)

use everywhere

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

Те, кто активно пользуются версией Perl 5.10, каждый раз пишут в начале файла инструкцию use v5.10 (в разных вариантах) или use Modern::Perl.

Брок Вилкокс создал (еще в августе 2009-го) модуль-прагму everywhere, и в документации прямо пишет о том, что сделал это для того, чтобы не писать надоедливые use 5.010.

Если вставить инструкцию everywhere до подключения других модулей, то ее аргумент автоматически превращается в соответсвующий вызов use внутри подключенных файлов.

use everywhere q(feature ':5.10');
use MyModule;

MyModule->my_sub($$);

Соответственно, внутри MyModule.pm теперь возможно использовать фичи 5.10:

package MyModule;

sub my_sub {
    say $_[1];
}

1;

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

use everywhere 'MooseX::Declare';

При попытке написать

use everywhere 'v5.10';

или

use everywhere '5.10.1';

появляется предупреждение о том, что v-string in use/require non-portable. Это удается обойти, написав переносимую (хотя и менее понятную человеку) конструкцию

use everywhere '5.010';

В качестве шутки можно избавиться от предупреждения и таким образом:

use v5.10;
use everywhere 'v5.10';

state (2)

| Нет комментариев

Хотя вчера я и написал, что ключевое слово state в перле похоже на static в C++, документация утверждает, что это не вполне так. Описано, впрочем довольно размыто.

Что еще нужно знать про state, кроме того, что эта инструкция стала доступна только с версии Perl 5.10?

Во-первых, state можно эмулировать и в ранних версиях.

{
    my $counter;
    sub counter {
        return ++$counter;
    }
}

print counter(), "\n"; # 1
print counter(), "\n"; # 2

Переменная $counter, оказываясь в замыкании, с одной стороны, недоступна для внешнего кода, а с другой, сохраняет свое значение между вызовами функции counter().

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

use v5.10;

sub counter {
    state $counter;
    ++$counter;
    return \$counter;
}

my $c = counter();
say ++$$c;        # 2
say ${counter()}; # 3

В-третьих, state-переменную допустимо инициализировать при создании, но это разрешено только для скаляров.

use v5.10;

sub counter {
    state $counter = 10;
    return ++$counter;
}

say counter(); # 11
say counter(); # 12

Попытка же инициализации списка или хеша приводит к ошибке:

state @a = (1, 2, 3);
Initialization of state variables in list context currently forbidden

state @a //= (1, 2, 3);
Can't modify private array in defined or assignment (//=)

В документации (perlsub) явно указано, что такие присвоения в языке не определены.

Тем не менее, при необходимости обойти это ограничение довольно просто.

state @a;
@a = (1, 2, 3) unless defined @a;

state (1)

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

Из записок технического менеджера.

A

За последние несколько дней несколько раз рассказывал, что моя жена в свое время преподавала в университете C++ студентам-физикам. Сам-то я до сих пор испытываю нереализованное желание писать на этом замечательном языке — первом, в котором я досконально и по-взрослому разобрался.

В C++ есть модификатор static, который в применении к переменной означает, что ее значение не нужно забывать между вызовами функции.

Б

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

В Perl 5.10 модификатор state делает то же самое, что и static в C++ — позволяет сохранять значение переменной между вызовами подпрограммы.

B

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

Сегодня как раз предоставился такой случай. Мне потребовалось выбрать случайную строку из большой базы данных. Разумеется, sort by rand() не подходит, а вот limit $N, 1 работает вполне быстро.

my $N = int rand $count;

Тут все понятно: чтобы узнать общее число записей $count, нужен еще один запрос (к тому же он с дополнительными ограничениями where). Вместо того, чтобы возиться с кешированием этой величины (memcached, BEGIN, etc.), достаточно поместить значение в статическую переменную, и вычислять ее, если она неопределена.

state $count;

unless ($count) {
    #
SQL-запрос select count(*)
}

my $offset = int rand $count;
#
SQL-запрос select ... limit $offset, 1

В файлик todo.txt заносится задача: использовать state совместно c defined-or (//).

Cравнить два списка — задача, которую без привлечения модулей (например, List::Compare) в перле решать не очень удобно.

Начинающих может удивить, что выражение @a == @b сравнивает не сами списки, а их размер.

С приходом Perl 5.10 возникает соблазн использовать для сравнения двух списков оператор смарт-матчинга (~~):

say @a ~~ @b;

Это хорошо работает до тех пор, пока в списках содержатся скаляры, например:

my @a = (1, 3, 5);
my @b = (1, 3, 5);
say @a ~~ @b; # 1

Однако следует помнить, что (по крайней мере, начиная с версии 5.10.1), операция сопоставления списков последовательно сопоставляет соответствующие элементы списков, используя тот же оператор ~~.

Поэтому следующий пример тоже напечатает единицу, хотя исходные списки — разные:

my @a = (1, 3, 5);
my @b = (1, qr/\d/, 5);
say @a ~~ @b; # 1

\K

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

В регулярных выражениях, доступных в Perl 5.10, появился метасимвол \K, который устанавливает точку «невозврата», до которой строка не должна измениться даже после замен.

Мой коллега порадовал еще раз, применив эту фичу в работе.

my $uri = $ENV{REQUEST_URI};
$uri =~ s{^.+?\K\?.*$}{};

Здесь в переменной $uri оказывается адрес без строки запроса, если она была.

Без использования метасимвола \K подобные замены приходилось делать явно, применяя захват и соответствующие переменные для подстановки:

$uri =~ s{^(.+?)\?.*$}{$1};

В документации замечено, что использование \K намного эффективнее (much more efficient), чем явная замена.

До Perl 5.10 аналогичная функциональность была возможна при подключенном модуле Regexp::Keep.

Почти два года назад появился Perl 5.10. Спустя год я начал более или менее размашисто применять его фичи на практике. А сегодня увидел в коде у коллеги интересную конструкцию с оператором defined-or (//).

Есть известный перлизм с вызовом die или warn, пристыкованным к действию, которое может завершиться с ошибкой:

open my $file, $filename or die "File not found";

А вот интересный прием с //:

do_something() // return NOT_FOUND;

Честно говоря, такая конструкция чем-то напоминает неадекватные инструкции в тернарном операторе:

is_leap_year() ? ($n = 366) : ($n = 365);

Но тем не менее показанное использование // весьма экспрессивно.

Страницы

  • img

Об архиве

Эта страница содержит последние записи категории Версии Perl.

Предыдущая категория — Веб.

Следующая категория — Видео.

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