Шрифт:
Итак, у нас есть язык с поддержкой параллельных процессов, и уже внутри них мы имеем самый настоящий Пролог с возвратами и всем прочим. Пролог, в котором там и сям сделаны срезы, чтобы избежать возврата, стал весьма детерминированным.
Сейбел: Где необратимые программы могут посылать сообщения другим процессам?
Армстронг: Да. Но это просто вызов функции, хотя, возможно, и не функции, запускающей ракеты. Это вызов функции, которая вызывает другую, а та - функцию, запускающую ракеты. По этой причине код, который вы создаете, становится все более функциональным, превращаясь в диалект Пролога - функциональное подмножество. А функциональное подмножество можно сделать полноценным функциональным языком.
Сейбел: Erlang сильно отличается от прочих функциональных языков, поскольку в нем есть динамическая типизация. Вы ощущаете свою принадлежность к сообществу функциональных программистов?
Армстронг: Безусловно. На конференциях по функциональному программированию мы спорим, выпячивая расхождения. Мы спорим о “жадных” и “ленивых” вычислениях, о динамической и статической типизации. Но несмотря ни на что, остается центральная идея функционального программирования: х не обозначает место в памяти, это неизменяемое значение. Мы задаем х равным 3, и дальше с этим ничего не сделаешь. Различные функциональные сообщества сходятся на том, что это крайне полезно для понимания программ, для параллелизма, для отладки. Однако есть функциональные языки с динамической типизацией, такие как Erlang, и функциональные языки со статической типизацией. У тех и других свои сильные и слабые стороны.
Было бы здорово, если бы Erlang пользовался преимуществами статической типизации. Возможно, в отдельных местах мы сумеем аннотировать программы так, чтобы типы стали более явными, тогда компилятор сможет порождать типы и генерировать более качественный код.
Сторонники статической типизации говорят: “Мы оцениваем сполна плюсы динамического подхода при маршалинге структур данных”. Мы не можем послать любую программу по проводу и воссоздать ее на другом конце - нам нужно знать тип. И вот мы имеем то, что Карделли назвал перманентно неконсистентной системой. Система, которая постоянно растет и меняется, при этом ее части могут быть временно неконсистентными. Если я меняю код, он не ведет себя как неделимый объект. Часть узлов меняются, остальные нет. Они общаются друг с другом - ведь в какие-то периоды времени они консистентны. А когда мы переходим через коммуникационную границу, как определить, что она проведена правильно? Тут надо кое-что проверять.
Сейбел: Когда-то вы отлаживали чужие программы за пиво. Почему вы считали себя большим специалистом по отладке?
Армстронг: Мне страшно нравилось заниматься отладкой. В какой-то точке программы распечатываешь переменные, что-то еще и смотришь, совпадает ли результат с ожидаемым. В одной точке программа может быть правильной, а в другой - нет. Надо смотреть посередине, потом еще раз посередине и так далее. При условии, что можно воспроизвести ошибку. Невоспроизводимые ошибки с трудом поддаются отладке. Но я сталкивался только с воспроизводимыми. Делишь участок кода пополам каждый раз, пока не найдешь. В конце концов ошибка обнаружится.
Сейбел: Считаете ли вы, что у вас был более систематический подход?
Армстронг: Да, другие попросту сдавались, неясно почему. Я не понимал, почему они не могут отладить. Как вы полагаете, отладка - трудное дело? По-моему, нет. Просто останавливаешь программу и прокручиваешь в замедленном режиме. Я сейчас говорю о пакетном Фортране.
Конечно, если говорить об отладке систем реального времени или программ чистки памяти, то я помню, как однажды “упал” Erlang. Это было в самом начале, сразу после запуска, я сидел и что-то настукивал - и Erlang “упал”. У него в оболочку было встроено что-то вроде команд Emacs. Набираешь erl, чтобы запустить его, и оказываешься в REPL [58] . Я набрал четыре-пять символов и сделал орфографическую ошибку. Потом я несколько раз сдвинул курсор назад, исправил, и он “упал” с ошибкой сборки мусора. Я знал, что это была очень, очень серьезная ошибка. Я попытался в точности вспомнить, что я настукивал, - там было около 12 символов - начал сначала, набил их, и все пошло без сбоя. Я сидел часа полтора, пробуя сотню разных штук. И вот снова сбой! Тут я все записал и смог приступить к отладке.
58
REPL (read-eval-print loop) - собирательное название интерактивных сред разработки языков семейства Лисп, Python, Ruby и др.
– Прим. науч.ред.
Сейбел: А чем вы пользуетесь? Операторами печати?
Армстронг: Да. Великие боги программирования говорят: “Вставь оператор печати в программу там, где, по-твоему, допущена ошибка, ре-компилируй и запусти”.
Еще есть Закон отладки Джо - не помню, вычитал я его где-то или сам придумал. Звучит он так: “Все ошибки будут не дальше трех операторов в ту или другую сторону от места последнего изменения программы”. Когда я работал в Шведской космической корпорации, мой начальник там раньше занимался “железом”. Мы были вместе с ним в Эсранге на севере Швеции - там площадка для запуска ракет и станция слежения за спутниками. Как-то раз он ломал голову, отлавливая ошибку в оборудовании, подсоединяя осциллографы, что-то меняя. Я спросил: “Может, я могу чем-нибудь помочь?” От ответил: “Нет, Джо, это ведь железо”. Тогда я сказал: “Это должно быть как в программах - ошибка недалеко от места последнего изменения”. Он подумал и сказал: “Ты гений! Я же поменял конденсатор”. Дело в том, что он заменил конденсатор на другой, более крупный. Мой шеф отпаял его, поставил тот, что был вначале, и все заработало. И это верно для всего. Ремонтируешь машину, что-то не так - причина в последнем действии. Всегда вспоминайте, что вы поменяли.
Сейбел: Вы доказывали когда-нибудь корректность своих программ? Импонирует ли вам такой формализм?
Армстронг: И да и нет. Я преобразовывал программы алгебраически, чтобы показать, что они эквивалентны, но никогда не применял доказательство через теоремы как таковое. Помню, когда я читал курс денотационной семантики, то отказался от этой идеи. Было дано упражнение: пусть х = 3иу = 4вх + у; докажите, что схема жадного вычисления, заданная уравнением таким-то, и схема ленивого вычисления, заданная уравнением таким-то, обе приводятся к 7.
Четырнадцать страниц лемм и прочего. Потом я подумал: “Ну как нее х = 3, у = 4, х + у = 7”. В то время я писал компилятор для Erlang. Если бы пришлось на десятках страниц доказывать, что 3 + 4 = 7, то доказательство правильности компилятора заняло бы не одну тысячу страниц.
Сейбел: Вы предпочитаете работать один или в команде?
Армстронг: Я люблю рабочую атмосферу в компании программистов: в целом я человек общительный. Но работать предпочитаю один. Нет, конечно, мне нравится сотрудничать с другими в смысле обсуждения проблем. Я всегда считал, что мысли, которые приходят в голову во время кофе-брейков, особенно по дороге туда и обратно, очень ценны. Бывает масса озарений. Отличная возможность объяснить свои идеи другим. Для меня важно переместить их из одной области мозга в другую. Часто, объясняя что-то, начинаешь лучше понимать задачу.