September 29th, 2011

glider

Макросам быть!

Часть 1, лирика
Часть 2, конкретика.

Позавчерашнее выступление на Скала митинге породило брожение умов. Как обычно: что-то кому-то лично говорить можно сколько угодно, но, когда все изложишь на бумаге и сделаешь презентацию - те, кто раньше молчали в приватных разговорах, начинают высказывать свое мнение.

Выяснилось, что Мартин предлагал мне начать с квазицитат совсем не потому, что ему они так сильно нравятся, а потому, что они могут быть непосредственно полезны для того, чем он сейчас занимается. А занимается он разработкой библиотеки интроспекции для Скалы. Но с чего бы Скале нужна интроспекция? Оказывается, для того, чтобы скопировать реализацию LINQ из дотнета. Как только я это осознал, то сразу понял, что надо спасать ситуацию.

LINQ представляет собой отлично задизайненное решение с точки зрения практичности, но вместе с тем приносит с собой фундаментальные ограничения, с которыми потом ничего не сделаешь. Например, знаменитый хардкод "если в каком-то месте требуется Expression<Func<T>>, а на входе Func<T>, то магически преобразуем тело функции в AST времени исполнения". Или, вот еще: "кроме лямбда-выражений ничего мы лифтить не будем". В результате получается своего рода изящная, но неортогональная языковая конструкция. Конечно, все эти острые углы надо заспецифицировать и потом поддерживать с ними обратную совместимость.

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

В итоге, все свободное время после выступления я потратил на то, чтобы придумать для Мартина пропоузал реализации линка на макросах. В этом мне крайне помогла крайне веселая сессия экспериментов с Немерле и советы ребят с форума RSDN. Детали я еще до конца не продумал (поэтому считайте этот пост дыбром - технических вещей в нем не будет), но в целом идея в том, чтобы реализовать методы вроде Where или Select в виде макросов. Так как макросы выполняются на этапе компиляции, они смогут работать с AST, а это как раз то, что нужно для LINQ.

Единственное, что оставалось - доказать прагматичность решения, т.е. реализуемость нужного для LINQ функционала в разумные сроки. Забаррикадировавшись в митинг-руме, я нарисовал схемку зависимостей между фичами, в результате чего выяснилось, что минимально необходимый набор функционала вполне компактен (сорри за отсвет от солнца - закрыть жалюзи не было возможности):



После того, как картинка была готова, я пригласил Мартина и рассказал ему про то, как сделать LINQ на макросах. На удивление, схему он смотреть не стал, и мы перешли к делу. Мартин оказался прекрасным собеседником - к вопросу он подошел без предубеждений и, в конце концов, мы вместе придумали общую картину того, как сабж можно интегрировать в scalac. Причем эта картина понравилась Мартину настолько, что он решил отказаться от копирования LINQ и пойти путем макросов. Я очень впечатлен таким уровнем демократии в нашей команде... и, конечно, очень счастлив! :)