Metaprogramming et al
От: Аноним  
Дата: 09.07.05 17:36
Оценка: 508 (52) +1 -2
Попробую объяснить, почему совершенного reflection/serialization/metaprogramming/etc.
framework'а для плюсов не будет никогда ;-(

Я долгое время был болен идеей создания Framework'а для С++ с поддержкой
удобной сериализации, reflection, расширяемого синтаксиса, метапрограммирования (например,
произвольной генерации proxy-классов и пр.) и прочей фигни в C++, с сохранением
темплейтов и пр. (Сам я много писал на C++, последние годы по работе пишу в основном
под .NET — C#/VB.NET). Много смотрел в сторону BOOST. Некоторый интерес представляет
и "quasireflection" в Qt, на котором построены signal-slots, QSA и пр. Достаточно быстро
убедился что и то, и другое, и прочие существующие решения не предлагают всего необходимого
для подобного "супер-мега-framework"'а. По сему я решил заняться кодогенерацией на основе
трансформаций AST (Abstract Syntax Tree). Посмотрев ANTLR и пр., я подумал, что лучше
(относительно) хорошего компилятора тяжёлый синтаксис C++ никто не распарсит, решил
использовать GCCXML.

С GCCXML история достаточно интересная -- это патч для GCC, который дампит наиболее
интересную информацию из AST в виде XML. Разработчики GCC активно сопротивляются
поползновениям по поводу включения таких фич в мейнстримный GCC, т.к. боятся, что
нехорошие коммерческие дяди начнут использовать GCC в качестве халявного frontend'а для
своих коммерческих компилеров, и GPL тут не поможет — никто ни с кем не линкуется,
просто подцепляется XML из GCC. Как следствие подобной политики, GCCXML существует
как отдельный продукт.

Далее была задача — как всё-таки обрабатывать эти самые деревья. Использовать DOM или
какие-либо иерархические структуры, написанные на тех же плюсах, всё-таки не очень удобно —
поэтому я решил использовать что-то специализированное. Сначала я попробовал XSLT.
Больших успехов я не добился, но неожиданно для себя обнаружил, что на этом языке,
лишённом даже таких простых вещей, как присваивание и циклы (кроме итераций по
nodeset'ам вроде <xsl:for-each>), можно сделать достаточно многое, используя
элементарную рекурсию. Это меня постепенно подтолкнуло к изучению языка Scheme.
Я достаточно быстро загорелся идеей создания ну-просто-сверх-очень-всесторонне-полезного
трансформера AST и кодогенератора C++ на Scheme, использующего пакеты
SXML/SXPath/etc. ( http://okmij.org/ftp/Scheme/xml.html ).

В Схеме меня привлекли две вещи — очень удобная обработка деревьев и списков,
как нельзя лучше подходящая для моей задачи, а также символьные выражения, которые
в очень многих случаях в десятки раз проще, чем XML, подходят для различных декларативных
языков (в данном случае я собирался использовать эту декларативность для компактного
описания трансформаций — например, формирования proxy-классов, кода для каких-нибудь
binding'ов и пр.) Также меня очень порадовал функциональный стиль программирования,
хорошо подходящий для "деревообработки".

Через достаточно непродолжительное время я для себя неожиданно обнаружил, что Схема,
оказывается, годится не только для "перелопачивания деревьев". Оказывается, можно
на полном серьёзе на подобных языках писать чуть ли не серьёзные приложения. Взять
хотя бы тот же SCSH ( http://www.scsh.net/ ) — заменитель Unix-shell'а. При программировании
можно использовать "гигиенические макросы" — название, ммм, неблагозвучное, но
это в ряде случаев существенно более удобный инструмент metaprogramming'а,
чем C++'ные templates, и Схему на Схеме генерить проще, чем C++ — ведь программа
по своей структуре — тот же список, состоящий из cons cells.

В то же время у Схемы есть ряд проблем — стандарт задаёт очень небольшой набор фичей,
к которым не относятся, например, объектно-ориентированное программирование.
В результате у каждой реализации свои классы, свои модули/неймспейсы
и т.д. В принципе юзабельно, но "корявовато". Как возможное решение, прежде чем
возвращаться к написанию ну-просто-сверх-очень-... трансформера, я решил глянуть
Common Lisp, язык, вроде бы похожий на Схему, в некоторых отношениях вроде бы
несколько менее элегантный, зато хорошо стандартизованный (стандартная библиотека
вроде как ни в чём не уступает C++'ной).

В результате я посмотрел на Common Lisp, и быстро понял, что на самом деле C++'у
никакие костыли не помогут, т.к. это не Лисп Почему именно — можно почитать можно
в целом ряде мест, например, тут -- http://www.gigamonkeys.com/book/introduction-why-lisp.html
(не говоря уже про товарища Грэхэма и пр.) Мощный компилируемый язык, с лучшей
поддержкой метапрограммирования и DSL, ох**тельной объектной системой (CLOS),
лексическими замыканиями, интерактивным стилем разработки (REPL), GC, развитой
системой исключений и т.д. и т.п. Проблема у этого языка одна: Лисп есть могучий
усилитель мысли, и тем, у кого мысли, как правило, отсутствует, он ничем не поможет
(т.к. нечего усиливать). Так что если человек собирается всю жизнь зарабатывать себе
на хлеб, таская контролы мышкой по формам, подобный инструмент пользы не принесёт.
С этим связана и сравнительно низкая распространённость языка и его странная репутация
(якобы медленный/трудный/нечитабельный/только AI/чисто академический/непригодный для
реальных приложений/интерпретируемый/чисто функциональный/без поддержки ОО/прочий БРЕД),
из-за которой я, ёлки-палки, столько лет программировал (и до сих пор программирую
по долгу службы) на всякой [ерунде].

Как следствие, мне стало ясно, почему C++'у не светит радикальное улучшение в области
того же метапрограммирования, расширяемых компиляторов и пр. Когда люди начинают
углублённо заниматься подобными вещами, пытаясь усовершенствовать язык, они неминуемо
обнаруживают, что нечто гораздо более _простое_ и удобное уже изобретено до них,
и нызывается оно Лиспом.

Кстати, о DSL (Domain Specific Languages), одной из наиболее сильных сторон Лиспа,
занятно пишет, надеюсь, небезызвестный товарищ Martin Fowler:
http://martinfowler.com/articles/languageWorkbench.html
Тов. Rainer Joswig (знаток Лисп-машин приводит пример решения задачи,
описанной Fowler'ом, на Лиспе:
http://lispm.dyndns.org/news?ID=NEWS-2005-07-08-1
http://groups-beta.google.com/group/comp.lang.lisp/msg/4fe888b58ffa83b8

Возникает вопрос -- если Лисп столь удобен, то почему же вещи типа Java, C#, C++,
Delphi используются гораздо более широко?.. Наиболее полный ответ на данный вопрос
дан Станиславом Лемом в произведении "О выгодности дракона" ("Звёздные дневники
Ийона Тихого") — http://lib.ru/LEM/lemitdr.txt, описывающий планету, на которой
жил, казалось бы, всесторонне вредный Дракон (занимал территорию, жрал туристов,
вонял и т.д.), от которого, тем не менее, не спешили избавиться:

"Если бы не дракон, для кого мы производили
бы трубопроводы, которыми в него качают мучной отвар? А ведь это — и
металлургические комбинаты, и трубопрокатные станы, и сварочные автоматы,
и транспортные средства, и так далее. Дракон имеет реальные потребности.
Ну, теперь понимаете? Производство должно на кого-то работать!
Промышленники не производили бы ничего, если бы готовый продукт
приходилось выбрасывать в море. Реальный потребитель — Другое дело. Дракон
— это громадный, необычайно емкий заграничный рынок, с колоссальным
спросом..."

Точно такая же ситуация оформилась в IT — если заменить дракона — миллионные армии не
желающих чему-либо учиться квазипрограммеров, ваяющих формочки и не желающих
слышать не то что про Лисп, но и даже про те же элементарные Design Patterns,
несколькими defmacro, то погибнет целая развитая индустрия по производству красивых
и удобных средств "разработки" для тех, кто в действительности по просту не умеет
программировать и, вместо того чтобы честно махать на улице метлой, протирает до дыр
ни в чём неповинные мышиные коврики.

"Благодаря" этому дракону мне лично приходится (надеюсь, только до поры-до времени)
писать не только на Лиспе, но и на шарпе, плюсах и дельфях. Делаю я это с отвращением,
но в то же время заметил, что, когда знаешь Лисп, на "inferior" языках программировать
становится в некоторой степени проще. Объясняется это тем фактом, что вещи, витающие
у тех же плюсовиков где-то между сознанием и подсознанием и затем посредством весьма
тернистого пути преобразующиеся в код, могут быть явно оформлены на Лиспе в виде
символьных выражений -- просто запиши свою мысль, а затем расставь где надо скобки.
Благодаря этому складывается гораздо более чёткое представление о сущностях типа
лексических замыканий и комбинаций методов, бледным отражением которых являются
паттерны проектирования. Более того, Лисп учит реально работать с теми же closures —
да, их добавили в C# 2.0 (+ они уже давно есть в JavaScript), но, скорее всего, большинство
шарповиков будет их юзать лишь для эвент хендлеров, т.к. о более серьёзных применениях
они и не подозревают.

Я уже не говорю о том, что, когда я работаю в супер-пупер-рюшечном VS .NET 2003, мне
до зубной боли не хватает элементарного Emacs+SLIME с его REPL'ом -- Command Window,
мягко скажем, не дотягивает. У меня начинают болеть пальцы при наборе пропертей
и тому подобной хрени (до чего удобны CLOS accessors!). Меня бесит, что там, где
я мог бы написать одну грёбанную функцию с keyword arguments, я должен писать класс
или кучу дурацких оверлоадов. Я это говорю, как профессиональный .NET программер
с далеко не самой низкой зарплатой среди присутствующих (судя по местным опросам;
воздержусь от конкретной цифры).

В общем и целом могу сказать следующее. У тех, кто сейчас пишет на плюсах, под .NET,
Java, Delphi и пр., есть только два пути не тратить почём зря своё время:

1. Смириться. Не пытайтесь расширить свою среду. У этих расширений есть потолок, и
не очень высокий. Кропайте методы, пишите message maps, не нравится — используйте
Qt/moc и пр. Не тратьте зря время на создание радикальных расширений. Да, работа
так и останется нудной, но что ж поделаешь, жрать-то надо. Создание крутых фреймворков
вместо реальной работы — хороший способ срыва проектов. И т.д., и т.п.

2. Учиться. Если у Вас есть немного свободного времени, потратьте его часть на изучение
языков, которые заставляют человека _думать по другому_. Изучите Lisp, Prolog, Haskell,
SML, Smalltalk, Erlang (особое внимание стоит уделить Common Lisp'у, как языку
расширяемому и наиболее практичному). Не давайте мозгам заржаветь, учитесь мыслить шире.
Для начала, это поможет Вам стать хорошим программистом, даже если на хлеб себе вы будете
зарабатывать, программируя на других языках. Все мейнстримные языки построены,
как правило, по принципу "те же яйца, вид сбоку". Осознайте, что мир на самом деле
не сошёлся на лежащем в их основе наборе стандартных парадигм.

Прошу прощения, если вышеприведённое чем-то напоминает поток сознания, писалось
всё урывками. Nevertheless I hope you'll find it useful


10.07.05 23:17: Ветка выделена из темы Metaprogramming et al
Автор: adontz
Дата: 07.07.05
— Павел Кузнецов
10.07.05 23:17: Перенесено модератором из 'C/C++' — Павел Кузнецов
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.