новости
статьи
.программирование

Rakudo: хорошо, круто, великолепно, плохо, скверно и странно

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

Кстати, за фразой «развернуть Rakudo» я подразумеваю буквально следующее:

$ svn co https://svn.perl.org/parrot/trunk parrot
$ cd parrot
$ perl Configure.pl; make
$ cd languages/perl6/; make perl6
$ ./perl6 -e 'say ~<Just Another Early Perl 6 Adopter>'


Использование инструментов на таких ранних стадиях, в которых сейчас находится и Rakudo, и Parrot, неизбежно сопровождается определенными неудобствами. Здесь о них рассказано не в качестве критики, а в качестве честных комментариев о текущей (а она быстро изменяется) реализации Perl 6 на Parrot. Кроме того, эти замечания могут служить напоминанием о том, что проект развивается благодаря тестерам, баг-репортерам, авторам патчей, документации и спецификации, и тем, кто уже сейчас пытается использовать Rakudo.

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

Многое из того, что здесь описано, встретилось в прокте November, реализации вики-движка на Perl 6.

хорошее

Многое из тех моментов, которые ожидает программист, знакомый с Perl 5, в основном работают. Список включает переменную $_, объявления my, ключевые слова if, while, for, sub, скаляры, массивы, хеши (с соответствующими функциями), map, grep, арифметические и строковые операторы. Поскольку эти конструкции образуют основу любой программы, их наличие в сегодняшнем Rakudo — это хорошо.

Манипуляции со строками — универсальный способ решения задач — почти доступны, включая очень детальную интерполяцию строк в двойных кавычках. В качестве дополнительного бонуса решать повседневные задачи форматирования помогает функция sprintf. Это очень хорошо.

Возможна работа с файлами, например, через open и readline. Возможно даже делать перебор строк в файле, используя префиксный итеративный оператор =. Это тоже хорошо.

Код может быть размещенн в отдельных файлах: use работает. Иметь возможность разделять код на модули — хорошо.

В подпрограммах (sub) можно пользоваться параметрами. Настоящими параметрами (даже с ограничением типа!), а не прототипами, как было в Perl 5. Если хочется, по-прежнему допустимо использовать @_ и shift, но это необязательно. Хорошо, что есть такой выбор.

крутое

В большой степени реализованы объекты и классы (спасибо Джонатану Вортингтону). Есть поддержка методов, атрибутов, атрибутов классов, конструкторов, ключевого слова self, наследования и переопределения, ролей и слова does, перечислений, динамической диспетчеризации и пространств имен. Иметь возможность программировать в объектно-ориентированном стиле на Perl 6 уже сегодня — это круто!

Реализовано ключевое слово given. Также есть подмножества, цепочечные операторы сравнения, объединения, неявные $_ в вызовах методов и неявные параметры в блоках. То, что сегодня все это доступно, — очень круто!

В Perl 5 полезным был модуль Data::Dunper, но даже его наличие в дистрибутиве не делает его элементом языка. Круто, что в Perl 6 можно вызывать метод .perl, не делая объявления use!

С августа модули могли быть заранее скомпилированы в стандартные PIR-файлы, и любая инструкция usе будет предпочитать файл Module.pir модулю Module.pm, что избавляет от ненужной компиляции соответствующего модуля. 17-кратное уменьшение времени исполнения от этого кеширующего эффекта — круто (спасибо Патрику Мишо)!

великолепное

В процессе компиляции важную роль в Parrot играет так называемый PGE, Parrot Grammar Engine. Это очень полезная реализация правил Perl 6 (спасибо, Патрик), которая применяется для разбора исходного кода и преобразования его в дерево разбора. Излишне говорить о том, что парсер способен понимать столько же, сколько и Rakudo, и уже достаточно развит.

Почти по Эшеру, сам PGE создан средствами Rakudo с использованием ключевых слов grammar, regex, token и rule. Там, где раньше приходилось применять специальные инструменты, чтобы создать парсер для программы, теперь возможно просто записать грамматику, а делается это так же легко, как классы на любом другом языке. Лексический анализатор и парсер автоматически генерируются «за сценой».

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

За несколько дней мы переписали наш модуль HTML::Template, заменив разрозненные регулярные выражения грамматикой. Код стал меньше (5,4 КБ до переделки, и 3,9 КБ после), и начал обрабатывать вложенные шаблоны! Грамматика создает дерево разбора шаблона, а метод с некоторым числом циклов и условий if обходит дерево и выполняет соответствующие действия. Добавление в будущем конструкции {*} (которая позволит встраивать код в регулярные выражения) позволит уменьшить код еще сильнее.

Согласно философии Perl, этот язык позволяет легкие задачи решать легко, а сложные — делать возможными. Новые же возможности по созданию собственных грамматик заметно смещает большую категорию проблем от сложных к легким. Это расширяет границы «практичного извлечения данных», которые Perl способен органично решать. Это просто великолепно.

плохое

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

Существует метод подстановки строк, названный .subst, который может быть использован для конструирования новых строк, заменяя некоторый шаблон некоторой строкой. Это намного менее функциональный инструмент, чем s///, но реализация последнего заставляет нас каждый раз использовать циклы while, переменные и .subst вместо более подходящего оператора s///, и это как-то плохо.

Нам не хватает многоточий, встроенных документов (heredocs) и присвоений с точкой. Иногда из-за их отсутствия код выглядит плохо.

Из-за многих нереализованных деталей поведения конструкций, управляющих ветвлением кода, в блоках given инструкции when при совпадениях не покидают охватывающий блок (а по спецификации должны). Хотя плохо это или нет, зависит от того, как вы собираетесь применять блок given.

Парсер не справляется с конструкциями типа return if $key == 0, поскольку модификаторы инструкций не распознаются, если они находятся сразу после них. Приходится писать return() if $key == 0. Необходимость ублажать компилятор из-за того, что он еще не полностью знаком с грамматикой Perl 6, — определенно плохо. (Особенно когда забываешь об этом и приходится выяснять, почему что-то не работает.)

Как уже говорилось выше, с помощью PGE в Rakudo можно делать сложные вещи, выраженные через грамматики. Сюда входит и создание собственных регулярных выражений, токенов и правил. Нельзя лишь называть их text, поскольку Rakudo увильнет, не объяснив причин. То, что нельзя использовать незарезервированное слово text в качестве идентификатора в грамматиках — плохо (пример такого поведения описан в уроке 20 в статье Морица Линца в этом номере журнала).

скверное

Пока еще невозможно делать смартматчинг с парами. Такое требуется для различных тестов свойств файлов, например, очень частой операции проверки существования файла. Такая проверка могла бы быть крайне простой: $file ~~ :e. Как мы проверяем сейчас? Мы открываем файл на чтение внутри блока try, и устанавливаем булеву переменную в True, если неудачный open к этому времени не привел к выходу из блока try. Оказалось, что это настолько частое действие в нашем коде, что мы вынесли его в отдельную подпрограмму. Но все-таки и это скверно.

Целые числа, большие миллиона (1_000_000), внутренне представлены как величины с плавающей точкой. Любые попытки воспользоваться двоичной арифметикой там, где она была бы уместна, например при работе с 16-битовыми числами, представляющими цвет (с помощью уже реализованных операторов ?&, ?| и ?^), вскоре превращаются в ужас.

Скверно, что вызывается метод, определенный вне класса. Конечно, этого легко избежать, но нужно ли вообще допускать такое? (Этот недостаток уже исправлен в ревизии r30990.)

Собирались использовать регулярные выражения в условии if или while, а затем прочитать переменную $/ внутри блока? Увы, невозможно, по крайней мере без повторного сопоставления внутри блока. Если у вас вложенные блоки, потребуется по одному сопоставлению на каждый блок, где нужна переменная $/. (Мориц Ленц предпочитает связывать эту переменную вместо повторного использования.) До тех пор, пока существует этот баг, приходится расплачиваться повторными сопоставлениями в начале блока, что уродует код. Исправлено в версии r30987.

странное

Как только ваш код достиг определенного размера, компилятор станет частенько приветствовать сообщениями Segmentation fault и Bus error даже в случае корректного кода. Удалите комментарий, и код вновь будет компилироваться. Спустя полчаса он опять рухнет; добавьте пустой оператор печати, и снова все хорошо. Такого рода эффекты безусловно относятся к разряду странностей. Скорее всего, проблемы будут разрешены к тому времени, когда сборщик мусора в Parrot станет более стабильным.

Подпрограмма, рекурсивно вызывающая себя внутри цикла for, приведет к совсем странному поведению. Что еще более странно, так это то, что этот баг появился после коммита в код Rakudo, который никак не должен был повлиять на программу в целом. С другой стороны, до коммита в этом случае вообще ничего не делалось, так что может быть это никогда и не работало. Странно.

в заключение

Пробуйте Rakudo уже сегодня! Шалости, словно игры новорожденного, — это хорошо, круто и великолепно. Если найдете что-то плохое, скверное или странное, напишите нам сообщение через канал #perl6 или на адрес rakudobug@perl.org; считайте это вашим вкладом в приближение Рождества.

Ссылки на документацию и на записи в реквест-трекере приведены в заметке Карла Мэсака, опубликованной в его журнале 29 августа:
http://use.perl.org/~masak/journal/37303.



Карл Мэсак (Carl Mдsak, Швеция), перевод Андрея Шитова
обсудить статью
© сетевые решения
.
.