пятница, 22 февраля 2008 г.

Осторожно, Perl!

Шуточная на половину статья, в которой упоминаются некоторые перловые хаки. Perl самый опасный язык программирования, поскольку он развивает "отвратительные" качества в людях. Некоторые их называют "добродетелями" программистов: лень, нетерпение, высокомерие (laziness, impatience, hubris).

Первоначально задумывалось достоинства Perl показать как недостатки, а недостатки - как достоинства. Но, кажется, немного отклонился в сторону. Даже думал, как Гоголь, предать огню эту статью, чтобы не пугать неокрепших духом, но потом решил оставить. Правильно поступил или нет - об этом судить читателю.

Вот собственно статья.

Среди множества языков программирования один занимает особое место. Это язык Perl! Если вы его не знает и получите предложения его освоить - бегите как можно дальше, иначе...

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

Причем это происходит постепенно и от того более коварным является этот процесс. Человек этого не замечает и даже потом, когда Perl полностью им завладевает, человек не будет это осознавать. Более того, он будет даже превозносить эти отвратительные черты, как великие добродетели программистов. Но какие это же добродетели!

Возьмем, например, высокомерие. Оно, якобы, помогает писать замечательные программы. Глупости все это. Высокомерие Perl программистов настолько велико, что они даже встревают в спор С++ и OCaml программистов о производительности их языков. Сам был очевидцем такого спора. В споре шел разговор как оптимально генерируется ассемблерный код, а также затрагивались вопросы оптимизации хвостовой рекурсии... Решили провести тесты, например, посредством вычисления чисел Фибоначчи.

А тут мимо проходил Perl программист. И что вы себе думает, он посмел высокомерно утверждать, что вычислит на Perl числа Фибоначчи быстрей чем они. Поспорили на бутылку коньяка. Программисты C++ и Ocaml знали, что из себя представляет Perl, поэтому сразу согласились на спор. Но они не знали, что из себя представляют Perl программисты. Кто бы мог подумать, что этот Perl программист выиграет спор! Он первый вычислил числа Фибоначчи! Когда остальные участники спора, отказываясь верить словам, подошли увидеть все своими глазами, Perl программист запустил на исполнение следующий код:

use strict;
use warnings;
use Memoize;
memoize('fib');

sub fib {
my $n = shift;
return $n if $n < 2;
fib($n-1) + fib($n-2);
}

my $n = $ARGV[0];
print "fin($n) = ", fib($n), "\n";

Конечно, для тех, кто знаком с модулем Memoize, все становиться ясно с первого взгляда.

Perl самый быстрый язык, не потому, что его интерпретатор быстр, а потому, что быстры и ясны мысли Perl программистов. Когда другие жонглирую байтами, Perl программисты не забывают об оптимизаций алгоритмов.

С дрогой стороны, Perl не только "самый быстрый язык", но и самый ленивый. Нет, не надо говорить, что самый ленивый - это Haskell. Вы бы посмотрели, как иногда Haskell программисты борются с ленивостью своего языка. Perl ленив по другому. Правильно, он ленив, потому, что ленивы его использующие люди. Кстати, и потому что они ленивы, они даже не нагружают свой компьютер лишней работой: вспомните про модуль Memoize. А ленивые списки и прочие есть и у Perl, например: Data::Lazy, Scalar::Defer, Object::Lazy, Tie::Scalar, Tie::StdScalar и даже DBIx::LazyMethod.

Perl также славиться тем, что "делает за вас вашу работу". Вроде-бы это очень хорошо, но постойте, это же самая большая "медвежья услуга". Со временем вы обленитесь и ваша лень не будет иметь границ.

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

Многие не в силах выдержать это, ломаются - бреют голову, посыпают ее пеплом и уходят в монастырь (http://perlmonks.org). Там они в спокойной обстановке, вдалеке от суетного мира занимаются каллиграфией, то есть обфускацией (http://www.perlmonks.org/index.pl?node=Obfuscated%20Code).

Лень привела также к тому, что Perl является сосредоточением множество закорлючер и заклинаний. (Про семейство APL языков скромно умолчу.) И все это преподноситься под соусом "cуществует более одного способа сделать это". Да ни один силач не поднимет книгу Perl рецептов.

А посмотрите, что Perl программисты сделали с совершенной и строгой концепцией Объектно-Ориентированного программирования!
Ну разве это объекты? Правда Damian Conway (Tie::SecureHash, Class::Contract) пытался образумить Perl программистов, да что толку. Как-бы в ответ, появились модули, позволяющие делать всевозможные хаки, залезать в чужие области видимости и менять значения локальных структур! Ужас! (Перечень модулей, опасных для неокрепших духом, вырезан цензором.) Хотя, надо отдать должное, на основе этих идей появилась реализация Аспектно-Ориентированного программирования на Perl (Aspect).

Так что, программисты, берегитесь Perl - это очень опасный язык! Когда Perl проникнет в ваши умы, вы никогда больше не сможете нормально писать на других языках программирования. И этому также будет способствовать то, что Perl из всех языков программирования дальше всего находиться от компьютера и ближе всего к человеку. Не дай Бой, вы из программиста станете писателем или поэтом. А ведь были уже прецеденты, например, королева поэзии Perl Sharon Hopkins.

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

Вы спросите, как же мне, использующему Perl, удалось избежать его пагубного влияния?
А у меня иммунитет - я же не программист. Я химик! :-

Коментарии и пожелания оставляте в http://kiev.pm.org/?q=node/157

среда, 6 февраля 2008 г.

Perl JSON модули с поддержкой UTF-8

Введение

Статья представляет обзор perl модулей для работы с JSON в контексте UTF-8. Подразумевается работа с UTF-8 на уровне символов, а не байтов. Если нужна работа на уровне байт, то подойдет любой из нижеперечисленных моделей, который устроит по скорости.

На CPAN существуют следующие модули:

  • JSON - parse and convert to JSON (JavaScript Object Notation).

  • JSON::XS - JSON serialising/deserialising, done correctly and fast

  • JSON::Syck - JSON is YAML

  • JSON::PC - fast JSON Parser and Converter (JSON::PC is a XS version of JSON).

  • JSON::DWIW - JSON converter that Does What I Want

В качестве тестовых данных будем использовать следующий JSON:

 { "hello":"Hello, \u00ab\u043f\u0440\u0438\u0432\u0435\u0442\u00bb \u2116 \u263a. Good by." }

В JSON содержится фраза ``Hello, <<привет>> #. Good by.'', в которой кавычки, номер и смайлик ``уникодные''. Именно как \uxxxx в JSON кодируются UTF-8 символы (http://json.org).

Этому JSON соответствует следующая Perl структура:

 { 'hello' => "Hello, \x{ab}\x{43f}\x{440}\x{438}\x{432}\x{435}\x{442}\x{bb} \x{2116} \x{263a}. Good by." }

Ну что-ж теперь приступим к тесту моделей.

Обзор модулей

JSON.

Для работы у UTF-8 в конструкторе необходимо это указать:

 JSON->new(utf8 => 1);

Модуль корректно ставит UTF-8 флаги, и обратном преобразовании кодирует UTF-8 символы. Но есть большое но: модель споткнулся на символах кавычки елочкой.

JSON::PC.

Как указано в документации на модуль, JSON::PC является XS версией модуля JSON, и как истинный приемник наследует туже проблему с русскими или французскими кавычками.

Модуль сам разбирается где UTF-8, ничего явно указывать не нужно.

JSON::Syck.

Модуль JSON::Syck написан сообразительной китаянкой, которая заметила что JSON по сути является YAML, и просто использовала библиотеку libsyck.

UTF-8 не поддерживается вообще, модель ориентирован на работу с октетами, о чем честно написано в документации. Подразумевается \uxxxx, а не ImplicitUnicode опция.

JSON::XS.

А вот модуль JSON::XS показал себя достойно со всех сторон. Правда перед преобразованием из JSON в Perl надо указать флаг utf8, а при обратном преобразовании - флаг ascii.

Из JSON в Perl:

 use JSON::XS;
my $json_xs = JSON::XS->new();
$json_xs->utf8(1);
$json_xs->decode($json_data);

Из Perl в JSON:

 use JSON::XS;
my $json_xs = JSON::XS->new();
$json_xs->ascii(1);
$json_xs->encode($perl_data);

Можно также задать флаг pretty для красивого форматирования результирующего JSON.

JSON::DWIW.

Последний модуль JSON::DWIW также ведет себе отлично, необходимо лишь в конструкторе сообщить об UTF-8:

 use JSON::DWIW;
my $json_dwiw = JSON::DWIW->new({ escape_multi_byte => 1 });
$json_dwiw->from_json($json_data);
$json_dwiw->to_json($perl_data);

Бонусы

Два пакета JSON::XS и JSON::DWIW нормально обрабатывают ситуацию, когда передаваемая им JSON строка не является последовательностью октетов, а является perl строкой с UTF-8 - не надо делать лишнюю проверку.

Benchmark

До этапа тестирования производительности успешно добрались лишь два модуля: JSON::XS и JSON::DWIW, - к которым нет ни одной претензии.

Собственно тест скорости на не слишком большой структуре:

 use Benchmark qw(cmpthese);
 cmpthese(10000, {
'JSON::XS' => sub {
my $json_xs = JSON::XS->new();
$json_xs->utf8(1);
$json_xs->decode($json_data_u);
$json_xs->ascii(1);
$json_xs->encode($perl_data_expected)
},
'JSON::DWIW' => sub {
my $json_obj = JSON::DWIW->new({ escape_multi_byte => 1 });
$json_obj->from_json($json_data_u);
$json_obj->to_json($perl_data_expected)
},
});

А вот и результаты:

               Rate JSON::DWIW   JSON::XS
JSON::DWIW 5246/s -- -78%
JSON::XS 24151/s 360% --

Вывод

Для меня вывод однозначен --- JSON::XS. Модуль ведет себя отлично с UTF-8, корректно преобразовывает данные в Perl строки и к тому же обладает приличной скоростью.

P.S. Для комментарий - http://kiev.pm.org/?q=node/153