June 25th, 2008

Book

Исторические предпосылки HN

Изучение языков программирования началось у меня по классической "институтской" схеме: Pascal -> Object Pascal -> C -> C++ . Затем продолжилось на коммерческой основе: C++ -> Perl -> Javascript -> PHP -> Haskell

С, PHP и Haskell оказались побочными ветками - на С я ничего существенного не писал из-за ОО-шумихи в начале 2000-х и распространенности к тому времени компиляторов С++. На PHP я в качестве менеджера и ведущего разработчика написал два больших проекта - веб-почтовик и веб-хостинг, после чего ушел из контор в самостоятельное плавание.

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

Javascript я начинал изучать с ASP3, сделав на нем сайт-базку, а затем продолжил, делая GUI на основе MS Html Applications и прикручивая его к C++ через COM.

На С++ я начал с ICQ-спамера, продолжив SMTP-спамером, клоном Remote Desktop, и распределенным (MPI/MPICH2) приложением на MSVC2005/Windows x64, которое пишу последние 4 года. Приложение занимается импортом анкет пользователей из спамерских баз. На входе - произвольные CSV-файлы до сотен гигабайт (разные разделители, форматы полей и порядок полей), на выходе - CSV-файл с распознанными анкетами в фиксированном формате, профильтрованные с использованием примерно 70 белых и черных списков. Где-то 15 KLOC на С++. Приложению постоянно не хватает памяти и скорости, что лечится оптимизацией. Архитектурно код разваливается - надо было 100 раз уже переписать, удается продолжать разработку только благодаря 800 регрессионным юнит-тестам.

Со временем я лучше узнал Perl, Javascript и Haskell) я понял, что  для реализации одной и той же функциональности на С++ требуется значительно больше кода, чем на других языках. Также, из-за ограничений языка я вынужден копипастить участки кода, которые на других языках можно вынести в библиотеку. По этой же причине я забросил Си и PHP и больше к ним не возвращаюсь, а также обхожу стороной C# и Java.

Иначе говоря, я почуствовал, что настало время забросить C++ и перейти на что-то более удобное. Но на что? Подходящего языка я не нашел, и решил сделать HN - собственный Domain-Specific Language, компилятор которого можно было бы завершить в течение месяца.
Book

Требования к замене С++ в моем проекте

Collapse )
Подводя итоги, новый язык должен иметь:
  • легковесную и малословную интеграцию с MSVC 2005-2008 x64
  • превосходную (как для языка, не являющегося Фортраном или С++) производительность
  • очень стабильный или очень маленький компилятор
  • развитые и синтаксически дешевые языковые средства:
    • параметрический полиморфизм
    • замыкания
    • вывод типов (не обязательно, но очень желательно)
Book

Вопросы, на которые должен ответить HN

Кроме практической ценности для моей работы, HN выполняет и образовательную функцию. Вот обновленная версия списка вопросов, которые я задал себе полгода назад:

Открытые вопросы

  • Какая фича сколько будет стоить, можно ли 80% возможностей реализовать с помошью 20% кода?
  • Какие фичи требуют наибольших усилий по реализации? Какие фичи современных языков самые прожорливые в плане разрастания исходного текста компилятора?
  • Какой язык получится, если жертвовать красотой и удобством языка ради простой и эффективной компиляции?
  • Может ли компилятор генерировать хороший читабельный код на выходном языке высокого уровня, и если нет, то чем это обусловлено?

Закрытые вопросы

Кто и почему ест производительность? Какие фичи современных языков самые прожорливые?
В основном производительность едят:
  • собранные на коленках генераторы native code
  • ленивость (косвенно, т.к. она влечет необходимость собирать на коленке graph reductor при написании компилятора и следить за "утечками" памяти при написании программ на ленивых языках)
Почему компилятор не в состоянии решить задачу распределения памяти статически (расставив на этапе компиляции все new и delete), а человек - может?
Компилятор прекрасно справляется с этой задачей, сборщик мусора или подсчет ссылок не обязателен. В области статического распределения памяти ведется много исследований, спрятанных под следующими ключевыми словами:
  • escape analysis
  • region inference
  • static reference counting
Более того, есть даже схемы обычного runtime reference counting, справляющиеся с циклическими ссылками.
Как именно реализуется нормальный порядок редукции? Зачем и в каких местах нужны thunks, реализующие вычисления по требованию? Как минимизировать количество thunks? Как минимизировать количество косвенных вызовов?
Отвечая на эти вопросы, можно писать диссертации. Вкратце - лучше отказаться от ленивых вычислений, пока не придумают способа эффективной реализации ленивых языков.
Насколько экспоненциальны экспоненциальные расходы при замене обобщенного кода на инстанцированный? Как ведет себя при этом общая производительность системы?
Изучение литературы показало, что в проектах моего масштаба инстанцирование полиморфного кода в мономорфный увеличивает производительность