воскресенье, 8 ноября 2009 г.

[comp.prog] Впечатления от интервью Джона Хьюза

На RSDN дали ссылку на интервью Джона Хьюза (вот прямая ссылка на интервью) – одного из разработчиков языка Haskell и автора инструмента QuickCheck.

Дядька явно умный, представитель т.н. академических кругов. Местами здравомыслящий:

Например, если вы посмотрите на Haskell, то есть определенные области программирования, в которых Haskell по настоящему превосходен, и есть другие области, в которых он совершено не подходит. Так, я не думаю, что Haskell полностью заменит C.

С другой стороны, он говорит:

…когда я начинал, мейнстримом были, наверное, Fortran и COBOL, и даже C был довольно новой штукой в то время. Пионеры функционального программирования говорили об увеличении производительности на порядок и я думаю, что функциональное программирование это обеспечило.

Если вы сравните Haskell-программы с C-кодом или даже C++ то часто они на порядок меньше и проще. Тоже самое и для Erlang, что сейчас находит подтверждение в индустрии.

Как-то это не очень согласуется между собой. Разве что во второй цитате он говорит об областях, где у Haskell/Erlang нет конкурентов. Что свойственно ученым: из всех имеющихся фактов ученым свойственно упоминать лишь те, которые доказывают их гипотезу ;) (старая шутка).

Хьюз говорит, что Haskell очень хорошо позволяет создавать DSL-и и это является одной из сильных сторон языка. Как по мне, так DSL-и (особенно internal DSL-и) не есть хорошо. Да, сейчас вокруг них существует много шума. И в каких-то областях DSL-и действительно очень полезны и важны (те же Regexp-ы или IDL-описания). Но это эпизодические случаи, которые имеют очень четкие границы применения. Однако, имхо, мало кто знает, во что превратиться программирование, когда большие программы будут собирать из десятков и даже сотен разношерстных DSL (как сейчас это происходит с библиотеками). Lisp-ы вот так же были хороши в DSL-естроении…

Довольно смешно было читать про то, как перейдя к программированию в среде с побочными эффектами (коей является Erlang), ему пришлось вспомнить, как же тяжело выискивать баги, вызванные побочными эффектами. Мол, столько лет я писал на чисто функциональном Haskell-е, а тут в Erlang-е приходится по нескольку часов заниматься отладкой, чтобы найти багу…

Да, кстати, приходится программировать на Erlang-е Хьюзу потому, что у Erlang-овской версии QuickCheck есть пользователи. Тогда как на Haskell-е в индустрии не больно-то заработаешь ;)

Вот чего я не понял в его рассказе, так это следующего фрагмента:

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

Не представляю я, как над кодом, задачей которого является производство побочных эффектов, можно построить интерфейс без побочных эффектов? Туп-туп. Буду признателен, если кто-нибудь сможет разъяснить мне это на пальцах или хотя бы выскажет идею на этот счет.

5 комментариев:

  1. > Как по мне, так DSL-и (особенно internal DSL-и) не есть хорошо.

    Я тебе по секрету скажу: каждый раз, когда ты проектируешь интерфейс компонента или библиотеки, ты создаешь internal DSL по обращению с этим компонентом или библиотекой.

    Именно поэтому ты не можешь легко заменять библиотеки в своей программе: у каждой - свой язык и свой набор идиом на этом языке.

    И когда говорят, что с такой-то библиотекой удобно работать - это значит, что она предоставляет пользователю выразительный internal DSL, который ведет к цели кратчайшим путем.

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

    ОтветитьУдалить
  2. >И когда говорят, что с такой-то библиотекой удобно работать - это значит, что она предоставляет пользователю выразительный internal DSL, который ведет к цели кратчайшим путем.

    Ты упускаешь еще один момент: интеграция нескольких библиотек в одном фрагменте кода. С библиотеками ситуация достаточно простая -- это просто вызовы функций. Например:

    SMTPClientSession session(...);
    MailMessage msg;
    msg.setSubject( subj );
    for_each( recipients, [msg]( const Recipient & r ) { msg.addRecipient( r ) } );
    session.send( msg );

    С internal DSL-ями сложнее -- они имитируют синтаксис нового языка. Что-то типа:

    SMTPClientSession.open session =>
    session.mail
    subject( subject )
    recipient( recipients )
    body( body )
    send;

    И вот тут встает вопрос: "а насколько удобно объединять в одном фрагменте разные DSL-и?" Что делать, если нужно вставить несколько получателей письма? Что делать, если нужно вставить нестандартный заголовок в письмо?

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

    MailMessage msg;
    setup_subject( msg );
    setup_recipients( msg );
    setup_headers( msg );
    session.send( msg );

    Смогу ли я так же переписать DSL-ный фрагмент?

    А что, если я захочу разные параметры устанавливать в параллель:

    MailMessage msg;
    parallel_do(
    []() { setup_subject( msg ); },
    []() { setup_recipients( msg ); },
    []() { setup_headers( msg ); } );
    session.send( msg );

    Позволит ли мне это делать DSL?

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

    ОтветитьУдалить
  3. ну, все нормальные библиотеки предоставляют оба интерфейса - как дсл-ный, так и обычный (например, Буст.Спирит).
    В результатена дсл-ном варианте интерфейса легко пишутся собственно грамматики, а на обычном - когда ты какие-то куски генеришь кодом.

    Ну и библиотеки - это не только вызовы функций, это и идиомы.
    Например, однофазной/двухфазное создание объектов.
    Или коды ошибок/исключения.
    Или ручной диспетчер сообщений/колбеки.
    И т.д.

    ОтветитьУдалить
  4. >ну, все нормальные библиотеки предоставляют оба интерфейса - как дсл-ный, так и обычный

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

    >Ну и библиотеки - это не только вызовы функций, это и идиомы.
    Например, однофазной/двухфазное создание объектов.
    Или коды ошибок/исключения.
    Или ручной диспетчер сообщений/колбеки.


    Вот с DSL-ями все это будет гораздо хуже. Т.к. сейчас хотя бы собственные обертки над чужими библиотеками можно делать (например, добавлять исключения или прятать их за коды возврата). А в DSL-е как разработчик DSL-я решит, так и будет.

    ОтветитьУдалить
  5. Не представляю я, как над кодом, задачей которого является производство побочных эффектов, можно построить интерфейс без побочных эффектов? Туп-туп. Буду признателен, если кто-нибудь сможет разъяснить мне это на пальцах или хотя бы выскажет идею на этот счет

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

    ОтветитьУдалить