среда, 25 мая 2011 г.

[prog.flame] Затрону таки тему Nemerle

RSDN-овские флеймы про Nemerle, как и советские газеты, я уже давно не читаю. Но после анонса релиза версии 1.0 на LOR-е время от времени просматриваю LOR-овское обсуждение. И вот на чем я себя ловлю: за все время, пока Nemerle мозолит мне глаза, я не встречал ни одного вменяемого объяснения преимуществ управления синтаксисом языка для прикладного программирования.

Главная фишка Nemerle, которую ставят во главу угла его евангелисты, – это синтаксические макросы. По сути, ядро языка очень минималистично. В нем нет даже таких привычных вещей, как if-ы и for-ы. Все это строится за счет синтаксических макросов, которые доступны не только разработчикам языка, но и пользователям. Любой прикладной программист может наваять свой собственный синтаксис для свой специфической задачи. Фактически, главное достоинство языка – это простое создание встраиваемых Domain Specific Languages (internal DSL-ей) для конкретных прикладных областей.

Ссылки по теме: #1, #2, #3.

Когда синтаксические макросы используются для формирования самого языка (if-ы) или его стандартной библиотеки (Regexp, LINQ и пр.), то это проблемы разработчиков языка и библиотек. Прикладных программистов это не касается. AFAIK, изрядное количество машинных команд IBM 360 реализовывались на самом деле не в процессоре, а через т.н. микрокод – набором совсем уж низкоуровневых команд процессора. И эта механика прикладных разработчиков нисколько не заботила.

Зато когда макросы начинают использоваться прикладными программистами, тут правила уже иные. Во всех спорах вокруг Nemerle всплывает один и тот же вопрос: ну и что делать, если Вася Пупкин придумал супер-пупер DSL, написал на нем туеву хучу кода, а затем свалил, а на проект пришел Ваня Сидоров? Что делать Ване Сидорову с этим DSL-ем, как с ним разбираться, как его сопровождать?

И вот на этот вопрос у Nemerle-истов я не видел вменяемых ответов. Стандартная отмазка – а когда Вася Пупкин оставляет после себя туеву хучу классов с методами – это разве не DSL? Разве с этим не приходится разбираться?

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

Как дело пойдет, если прикладные задачи начнут решаться посредством комбинирования DSL-ей – вот это terra incognita. В истории разработки ПО соответствующих крупномасштабных экспериментов было всего нечего. Самый большой – это Lisp. Который уже давным-давно не мейнстрим и серьезного влияния на мейнстрим не оказывает. Т.е. процент разрабатываемого на Lisp-е ПО находится где-то в рамках статистической погрешности ;) Но как раз на примере Lisp-а можно видеть, что DSL-естроение черевато. Интересующихся адресую к Social Problems of Lisp ;)

Было время, когда я увлекался мелкими DSL-ями – это были интересные эксперименты, но не более того. Хотя даже исходя из своего скромного опыта могу указать одно важное преимущество кучи классов/методов перед DSL-ями: чужое API (на важно, объектное или процедурное) не сложно инкапсулировать в свое собственное API. А вот с DSL-ями так не получится.

Т.е., если у нас есть “чужой и корявый” API для какой-то прикладной области, то мы можем построить вокруг него свой “правильный и красивый” фасад. Взять, например, библиотеку libcurl. Да, она работает, да в ней все уже давно сделано. Но пользоваться ей – убиться веником :) Однако, всего несколько простеньких утилитных классов превращают это неблагодарное занятие во вполне себе нормальное и не лишенное некоторой приятности ;) В случае с API такой фокус прокатывает. А вот в случае, если бы libcurl была представлена как расширение синтаксиса?

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

NN​ комментирует...
Этот комментарий был удален автором.
NN​ комментирует...

Удивительно, что еще нет комментариев :))

Отмазка конечно плохая.
Но на самом деле все не так плохо как кажется.

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

Скажем Linq в Nemerle сейчас записываться так:
linq <# from i in ... select #>

Т.е. мы имеем тут "linq" в виде ключевого слова.

Скорее всего в нашей библиотеке будет не linq, а другой скажем:
myliq <# MySyntax #>.

(Кстати <# #> это не магия, а всего лишь аналог " ", но позволяет рекурсию и вставлять кавычки).

Далее, любой макрос можно вызвать непосредственно без синтаксиса:
Nemerle.Core.@if(a > b, true, false)
Вместо
if (a > b) true else false.

Так же и с Linq:
Nemerle.Linq.LinqMacro( expression )
или
Nemerle.Linq.ToExpr( expression )

Далее, для коллизии еще нужно подключить два пространства имен в один файл.
Тоже не обязательно частый случай.
Напомню, каждый макрос лежит в пространстве имен, а значит если его не заюзать (using) то коллизий не будет вообще.

Но допустим мы хотим использовать две библиотеки и в обоих есть одинаковый синтаксис. (Что может случится даже с обычными функциями в С)
Самый простой вариант, сделать класс частичным (partial) и в двух файлах использовать разные библиотеки.
Или же вызывать одну из них непосредственно, если уж очень нужно.

К слову сказать, в Nemerle есть решение проблемы.
Возможно высказывания на RSDN были не очень понятны.
Надеюсь теперь все встало на места.

Ну или если имеются вопросы, милости просим.

eao197 комментирует...

@NN

>Nemerle.Linq.LinqMacro( expression )

При этом возникает вопрос: а зачем тогда все это? Вон во всех мейнстримовых языках пишут почти что так сразу. И никаких проблем.

Так что я вполне понимаю, зачем макросы разработчикам языка. Но вот зачем они прикладным программистам?

NN​ комментирует...

Ну вот часто встречается какой-то паттерн и уже достало :)
Быстро пишем макрос с синтаксисом и все пучком.

Вот скажем был макрос foreach, а захотелось улучшить , добавил foreach-otherwise.

И все красиво выглядит:
foreach (...) otherwise ...
Вместо там
SomeMagicFunction(p => foreach (...) { })

Я бы не сказал что это нужно всегда и везде.
Но как инструмент может быть полезен.

Вообще макросы нужны прикладым программистам.
Я не про те которые синтаксис меняют, я вообще говорю.

Скажем макрос который добавляет номер ревизии SVN в AssemblyInfo. Удобная штука, не надо писать отдельную программу. Все в одном билде.

Вот, кому-то нужен был макрос для эмуляции скопов С++. (SurroundWith)
Сначала сделан макрос для себя, а потом вошел в состав компилятора.

Вот я сделал макрос который генерирует перегрузки функции.
F(a : int = 1, b : int = 2)
( Правда он недоделан, и не входит в поставку компилятора :) )

Создаст 2 функции с 0 и 1 аргументами.
Для лучшего интеропа с C#.

Чем не прикладная задача ?

Тут сложно искать, это в процессе работы выяснить можно что нужно а что нет.
Вот в C# если повторяется один и тот же паттерн много раз разумно его вынести в метод, но если метода и класса недостаточно ? Тут помочь может макрос.

eao197 комментирует...

@NN

>Я бы не сказал что это нужно всегда и везде.

Так собственно, в это и упирается. Если нужно далеко не всегда и не везде, то это вовсе не преимущество конкретного языка в области прикладного ПО.

А разные фокусы вроде foreach-otherwise и самодельных перегрузчиков функций -- так за это в Ынтерпрайзе по рукам бьют. И заслуженно в большинстве случаев. Поскольку в долгосрочной перспективе SomeMagicFunction обходится дешевле.

NN​ комментирует...

Это премущество когда это понадобится.

Вот в С++ можно жить без лямбд, но когда они понадобились в коде, то уже поздно.

В Nemerle как раз, как только мы видим, что можно ускорить и упростить разработку, можно написать макрос.

К примеру макрос для юнит тестирования.

Или другой сценарий.
Мы хотим дать клиентам (другой конторе) возможность конфигурировать, но не хотим ХМЛ (достал :) ) и не хотим писать свой скриптовый язык.
Можно в Nemerle реализовать DSL и предоставить его как API.

DSL в Nemerle использовать можно в разных целях.
Для создания парсера (Nemerle.PEG) , для вычислений (Computation Expression). Еще один вариант DSL-я для работы с физическими размерностями .
На RSDN был тут код позволяет в красивом виде описать как сопоставляются размерности и их использовать со статической проверкой.

velocity = length / time.

def l = 1m;
def t = 1s;
def v = l/t;

Бить по рукам за улучшенную жизнь это конечно сурово.
Ну вот есть в Nemerle using..catch
Его нет в C#.

Не было бы его в Nemerle, чем было плохо реализовать такой макрос для себя если похожий код повторяется 100 раз?

Согласен нужно подходить более осмысленно. Но вот макросы в С++ пишут, значит без них в С++ трудно :)
А за макросы не все по рукам бьют.

А тут статический контроль, размещение в пространства имен. Возможность отладки.
Кто не хочет, просто не юзает и нет проблем.

Самое главное, что код на выходе (бинарник) с макросом и без вполне может быть 1 в 1 :)

eao197 комментирует...

@NN

>В Nemerle как раз, как только мы видим, что можно ускорить и упростить разработку, можно написать макрос.

Если разработчики компилятора видят способ за счет макросов увеличить скорость разработки компилятора -- это одно дело.

Другое дело, когда какой-нибудь Вася Пупкин при решении проходной задачки, скажем, по импорту данных из большого csv-файла в несколько БД напишет свой миниязычок. А сменивший его Ваня Сидоров скажет -- чо за ущербная хрень? Она и того не умеет, и этого, и сопровождать это невозможно, лучше свой DSL сделать.

>Но вот макросы в С++ пишут, значит без них в С++ трудно :)

Java и C# уже давно доказали, что в области прикладного ПО у C++ ниш осталось совсем немного. И его макросы этому так же поспособствовали.

Пример с размерностями в других языках может быть записан не сильно хуже и без макросов.

NN​ комментирует...

Ну такое можно сказать и про библиотеки.

Вася Пупкин написал тут врапперы C# для WinAPI отстой просто.

Тут надо понять, что в Nemerle макробиблиотека не отличается в плане понятий от библиотеки в других языках.
Ну и снова, всегда можно вызвать макрос напрямую, переделать DSL ну и в крайнем случае поговорить с разработчиком =)

Как раз Java,C# показали что макросы нужны.
Скажем паттерн прокси, без макросов просто жуть.

Тут вот пробегал вопрос, что лучше в С++ наследовать или аггрегировать и проксить методы.
Так правильно это проксить, но без макросов типа Nemerle уже проще наследовать и пофигу.
А в Java,C# вообще нет выбора :)

Вообще у С++ много проблем кроме макросов ^_^

Пример с размерностями может быть записан хорошо если язык позволяет, а положим он не позволяет сделать это красиво.
Можно как в С++ извращаться конечно.

Да, можно без макросов. Но зачем все время придумывают тогда кодогенераторы ?
Тот же ASP.Net, T4, Razor и другое.

В случае Nemerle это можно просто внести на уровне библиотеки без внешней утилиты.


Мне кажется, слухи о проблемах сильно преувеличенны.
Просто так никто не будет писать себе DSL без причины.
Как просто так никто не использует Boost.Preprocessor и метапрограммирует, как просто так T4 никем не пользуется.
Можно также дать возможность использовать все как в виде методов, так и в виде DSL.


P.S.
Достаточно просто запретить создавать макросы без согласования с тимлидером.

eao197 комментирует...

@NN

>Ну такое можно сказать и про библиотеки.

Вася Пупкин написал тут врапперы C# для WinAPI отстой просто.


Как раз об этом я и писал в своем посте -- несколько десятилетий широкого промышленного программирования доказали, что это не проблема. Не нужно переписывать врапперы Васи Пупкина -- можно над ними написать свои.

>Как раз Java,C# показали что макросы нужны.

Осталось выяснить кому. Я общался с разными Java-истами, многие из которых как раз радовались тому, что в Java нет возможности так извращаться и решать проблему 10 разными способами, как в C++.

>Но зачем все время придумывают тогда кодогенераторы ?
Тот же ASP.Net, T4, Razor и другое.

В случае Nemerle это можно просто внести на уровне библиотеки без внешней утилиты.


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

NN​ комментирует...

Как раз об этом я и писал в своем посте -- несколько десятилетий широкого промышленного программирования доказали, что это не проблема. Не нужно переписывать врапперы Васи Пупкина -- можно над ними написать свои.

Тогда почему в случае Nemerle это сделать нельзя ?

>Как раз Java,C# показали что макросы нужны.

Осталось выяснить кому. Я общался с разными Java-истами, многие из которых как раз радовались тому, что в Java нет возможности так извращаться и решать проблему 10 разными способами, как в C++.

Отсутствие лямбд тоже радует Java-истов, но никак не радует меня. :)
Я полагаю, что тебе тоже не нравилось что не было генериков до 5.0.
А до их появления, гарантирую, что некоторые радовались, что их нет.
Но вот появилось.
Как в C# не было аргументов по умолчанию и расписывали это как преимущество надо С++ ! Но в 4.0 вдруг это стало фатальным недостатком, и пришлось добавить.

Мне кажется тут это больше дело привычки.
Не исключено, что решать задачу одним способом лучше, но тогда уж наилучшим, а не кабы-каким ! *THUMBS UP*

В случае Nemerle это можно просто внести на уровне библиотеки без внешней утилиты.

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


Аналогично Nemerle. Подключаем либу и пользуемся.
Не хотим, не пользуемся.

Библиотека развивается отдельно, моя программа отдельно.
Я не вижу разницы.

eao197 комментирует...

>Тогда почему в случае Nemerle это сделать нельзя ?

Так а где примеры этого? Все, что приводится -- это как вызывать синтаксические макросы в виде функций.

Например, в C++ или Java у меня может быть большой исходник, в котором понатыканы вызовы библиотеки A. В какой-то момент я написал B, которая является врапером для A. Я могу не переписывать весь исходник, а задействовать B только в нужных мне местах.

Теперь представим, что дело происходит в Nemerle, а A -- это библиотека с макросами. Сколько работы мне потребуется проделать, чтобы добавить в исходник использование библиотеки B?

>Отсутствие лямбд тоже радует Java-истов, но никак не радует меня. :)

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

В Nemerle ситуация иная -- там изначально разработчику дается big gun. Забрать который уже не получится.

eao197 комментирует...

>Аналогично Nemerle. Подключаем либу и пользуемся.
Не хотим, не пользуемся.


Не очень понимаю. Допустим, я взял lex (flex) или ragel и сгенерировал себе лексический анализатор. Далее я могу таскать с проектом только результирующий c (cpp, rb,...) файл. Ну и исходный l-файл может где-нибудь валяться. Код анализатора генерируется один раз и все.

В случае с библиотекой Nemerle, как я понимаю, библиотеку постоянно придется таскать с собой. Ведь она будет вызываться при каждой компиляции. Правильно?

Eugeniy комментирует...

>> Допустим, я взял lex (flex) или ragel и сгенерировал себе лексический анализатор. Далее я могу таскать с проектом только результирующий c (cpp, rb,...) файл. Ну и исходный l-файл может где-нибудь валяться. Код анализатора генерируется один раз и все.

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

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

ИМХО, часто очень удобно вместо кучи отдельных программ для билда проекта использовать одну.

Eugeniy комментирует...

И еще насчет макросов - вот например в Java нету аналога using C#. И никак его туда сам не добавишь. Поэтому приходится на каждый чих писать try finally, что создает массу "мусорного" кода.

Если бы в яве были макросы, каждый создал бы свой using, и было бы их как строк в С++ :) Это конечно не сильно здорово, ибо все эти using использовались бы немного по разному, назывались бы тоже по разному. Однако, ИМХО, это все равно лучше текущей ситуации.

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

На чистом С тоже можно нагородить ужасный ужас (и даже не используя макросы), хотя язык довольно прост...

Unknown комментирует...

Если проект уныл как стадо бегемотов а программисты перебегают при первом взмахе N-долларовой бумажки в соседнем офисе - то надо писать на Java, а лучше на Delphi. ...А если харизма руководителя позволяет вообще ничего ничего не иметь по итогам проекта, то и Basic не следует брезговать.
С другой стороны, если в проекте есть чем заняться, помимо самовыражения а макросах, а люди задерживаются хотя бы на пару лет... Хм, как ситуация, что не осталось никого, кто знает как код работает, вообще возможна в более-менее вменяемой компании?

jazzer комментирует...

проблема внешнего кодогенератора (и преимущество встроенного макроса) - это то, что внешний кодогенератор ничего не знает о языке, системе, типах и прочем.
Т.е. внешний кодогенератор работает только в примитивных случаях, для чего-то посложнее приходится извращаться и с матом выкидывать кодогенератор - у меня уже несколько раз так было.
И сишные макросы не спасают, именно потому, что они тупые, почти как кодогенератор (отличаются от него локальностью генерации). А вот полноценные макросы, котороые понимают, откуда их вызвали (из какого класса/пространства имен/функции, какие у окружения свойства и т.п.) - это то, чего мне лично страшно не хватает в С++, потому что использование этой информации сделает код гораздо чище и понятнее.

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

eao197 комментирует...

@Eugeniy:

>И еще насчет макросов - вот например в Java нету аналога using C#. И никак его туда сам не добавишь. Поэтому приходится на каждый чих писать try finally, что создает массу "мусорного" кода.

Как будто наличие синтаксических макросов сразу сделает ситуацию лучше. Ведь using -- это не только синтаксическая конструкция. К ней должны еще прилагаться: интерфейс IDisposable, реализация этого интерфейса в соответствующих классах стандартной библиотеки, реализация этого интерфеса в собственных классах, соответствующая поддержка using-а в runtime (перехват исключений, их подавление и продолжение цепочки вызова dispose из других using-ов).

Так что, если любой желающий получит возможность плодить свои using-и, то это будет еще похлеще зоопарка string-ов в C++.

eao197 комментирует...

@Eugeniy:

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

В точности то же самое будет и с кодогенератором на макросах. Только вот с внешним кодогенератором, если вам больше не нужно развивать описание для кодогенератора, то вы можете зафиксировать в проекте готовый выхлоп кодогенератора и все. Ничего больше таскать не придется.

eao197 комментирует...

@jazzer:

У меня впечатление, что мы сейчас о несколько разных вещах говорим. Я говорю о ситуации, когда кто-то решает: "Для удобного использования libcurl я сделаю такой DSL" и делает что-то вроде

auto ctx = curl_define
post
on URL("http://...")
ostream request_data
istream respose_receiver
header "Connection: Keep-Alive\n"
default_timeout;
ctx.perform;

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

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

Имхо, это более важная и полезная штука, чем изменение синтаксиса языка для DSL-естроения. И не факт, что макросы -- это лучший способ для ее реализации. Возможно, есть и другие способы. Например, какое-то развитие compile-time function evaluation из языка D.

eao197 комментирует...

@CheatEx:

>Хм, как ситуация, что не осталось никого, кто знает как код работает, вообще возможна в более-менее вменяемой компании?

Хм... Ну вот покажи мне мой собственный код 3-5 летней давности, я весь с ходу не скажу, как он работает.

Eugeniy комментирует...

>> В точности то же самое будет и с кодогенератором на макросах.

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

>> Только вот с внешним кодогенератором, если вам больше не нужно развивать описание для кодогенератора, то вы можете зафиксировать в проекте готовый выхлоп кодогенератора и все. Ничего больше таскать не придется.

Ну выхлоп макросов - это аст. Наверное в принципе можно этот аст сохранить и подсовывать компилятору.

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

>> К ней должны еще прилагаться: интерфейс IDisposable, реализация этого интерфейса в соответствующих классах стандартной библиотеки, реализация этого интерфеса в собственных классах, соответствующая поддержка using-а в runtime (перехват исключений, их подавление и продолжение цепочки вызова dispose из других using-ов).

Да, мне, как автору my_own_using придется потратить пару дней и сделать реализации IDisposable для классов стандартной бибилиотеки, которые я использую (если язык предоставляет макросы, то наверное есть какой-то механизм так сделать. Например неявное приведение в Scala или расширенияв c#), а также реализовать этот интерфейс для своих классов. Кроме того, надо будет написать и отладить my_own_using, чтобы он корректно отрабатывал исключения.

Но зато потом я буду просто использовать my_own_using, код станет чище и понятнее мне. Если мой код будет читать Вася, то ему придется почитать документацию по my_own_using. Ну так в моем коде еще тонна классов, по котором Васе также придется почитать документацию, так что оверхед от my_own_using невелик.

>> Так что, если любой желающий получит возможность плодить свои using-и, то это будет еще похлеще зоопарка string-ов в C++.

Ну а какой выход? Только стандартный using в стандартной библиотеке. А его нет. Возьмите например какое-нибудь хитрое дерево, которого нет в JFC. Я напишу собственную реализацию, Вася возьмет библиотеку А, петя - бибилиотеку Б. Все эти реализации будут по разному работать и по разному использоваться. Если нам придется поддерживать код друг друга, надо будет или вникнуть во все три дерева, или переписать код под какое-то одно.


>> И использует его в своем коде. А потом другой разработчик пытается применить этот DSL у себя и сталкивается с какими-то ограничениями DSL-я, о которых автор DSL даже не думал.

Я все еще не могу понять, почему DSL над libcurl хуже в этом плане обычного враппера над libcurl. С тем же успехом я могу написать жуткий и совершенно нерасширяемый враппер. Когда мой код попадет к Васе, тот вероятно перепишет его. Вначале ему придется разобраться в моем враппере. Если заменить враппер на dsl - что принципиально изменится?

NN​ комментирует...

Так а где примеры этого? Все, что приводится -- это как вызывать синтаксические макросы в виде функций.



Например, в C++ или Java у меня может быть большой исходник, в котором понатыканы вызовы библиотеки A. В какой-то момент я написал B, которая является врапером для A. Я могу не переписывать весь исходник, а задействовать B только в нужных мне местах.

Теперь представим, что дело происходит в Nemerle, а A -- это библиотека с макросами. Сколько работы мне потребуется проделать, чтобы добавить в исходник использование библиотеки B?


Давай по порядку :)

Если макросы не синтаксические, т.е. метаатрибуты.
То тут вообще просто.
Можно указать полное имя там где неоднозначность.
Точно так же как и аттрибуты в C#.
Тут проблем нет.

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

Допустим у нас синтаксические операторы макросы, т.е. &&, ||, и т.п.
Снова же, всегда можно написать макробиблиотеку которая обернет и сделает что нам нужно.

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

И снова же, для простого случая достаточно разделить файл на две части и нет проблем.

Может быть это проскользнуло, в Nemerle можно написать враппер над макробиблиотекой. В этом нет никаких проблем.

Еще вопросы ?:)


Если все же непонятно, давайте что ли примеры кода и там разберемся.

NN​ комментирует...

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

Я могу аналогичное сказать про любую библиотеку. И не всегда можно что-то сделать.

Скажем есть код в System.* где я сталкиваюсь с ограничениями , о которых авторы не думали.
И что делать ?

Тут хоть можем иметь исходник , который можно подправить.

eao197 комментирует...

@NN:

>Не скажите. Кодогенератор на макросах - это просто внешняя библиотека. Геморроя с подключением внешней библиотеки обычно несравнимо меньше, чем с подключением внешней тулзы

Это до тех пор, пока не возникнут несовместимые зависимости. Например, A нуждается в B v.1.0.3, а C в B v.1.5.4. При этом v.1.0.3 и 1.5.4 не совместимы между собой.

>Но я честно говоря не понимаю, на кой это вообще надо. Как вы определите, что можно зафиксировать выхлоп? А если вы ошиблись, и через полгода все же понадобится подкорректировать исходник?

У меня было несколько случаев, когда приходилось использовать yacc/bison. Так я на своей машине устанавливал нужную версию yacc-а, разрабатывал грамматику, а затем в проект помещал только y-файл и выхлоп yacc-а. После чего это годами жило в проекте, поскольку изменений в грамматике не требовалось. А когда требовалось, то просто опять на время разворачивался yacc.

>Но зато потом я буду просто использовать my_own_using, код станет чище и понятнее мне.

Так в этом и вся проблема. Сейчас мне my_own_using проще и понятнее. Через 3 года мне уже не так проще, и не так понятно. А лет через 7 вообще приходится все это выбрасывать. Тогда как "топорный" код хоть и требует больших усилий по первоначальному написанию, зато потом обходится дешевле.

eao197 комментирует...

@Eugeniy:

>Я все еще не могу понять, почему DSL над libcurl хуже в этом плане обычного враппера над libcurl. С тем же успехом я могу написать жуткий и совершенно нерасширяемый враппер. Когда мой код попадет к Васе, тот вероятно перепишет его. Вначале ему придется разобраться в моем враппере. Если заменить враппер на dsl - что принципиально изменится?

Во-первых, история развития ПО показала, что библиотеки развивать и сопровождать проще, чем DSL-и. Lisp или Forth, которые как раз провоцируют на использование DSL-ей, сейчас нужно с микроскопом искать.

Во-вторых, в ООП библиотеках есть возможность для маневра за счет наследования и переопределения виртуальных функций. Что позволяет делать более-менее приемлимые надстройки над "корявыми" библиотеками.

В-третьих, вы можете написать свой враппер над libcurl и использовать его параллельно с чужим враппером в том же самом коде. Не думая о совместимости синтаксисов и разнесения разных фрагментов по разным файлам.

eao197 комментирует...

@NN:

>Хочу напомнить, что коллизия произойти может только в случае использования двух макробиблиотек в одном файле, и которые определяют один и тот же макросинтаксис.
Шансы на это не высоки.


Вот на этот счет у меня другое мнение. Часто как бывает? Есть работающий код, не всегда тривиальный. Внезапно выясняется, что нужно исправить его поведение в какой-то нестандартной ситуации. В старый код нужно добавить новый фрагмент. Но старый код использует старую библиотеку. Которая мне по множеству причин (ее писал не я) не нравится и я хочу задействовать свою, очень похожую, но правильную ;)

NN​ комментирует...

Вот на этот счет у меня другое мнение. Часто как бывает? Есть работающий код, не всегда тривиальный. Внезапно выясняется, что нужно исправить его поведение в какой-то нестандартной ситуации. В старый код нужно добавить новый фрагмент. Но старый код использует старую библиотеку. Которая мне по множеству причин (ее писал не я) не нравится и я хочу задействовать свою, очень похожую, но правильную ;)

В гипотетическом случае, возможен конфликт, которой разрешить будет сложно.
Но ведь это возникает и не только с макросами.
Вон с зависимостью lib сколько проблем. Тому нужна версия одна, а другому другая и хочется все вместе..

Мне кажется, что многие проблемы немного преувеличены.
Да, сценарий вероятен.
Но всегда есть возможность выйти из ситуации.

Рассмотрим такой сценарий, мы имеем библиотеку с закрытым кодом.
Она реализует DSL для чего-нибудь.
В ней нет нужной нам функциональности.
Разработка библиотеки больше не ведется. Что делать ?
В крайнем случае мы можем написать свою библиотеку с DSL, которая будет вызывать первую.
И там добавим то, что нам необходимо.

Точно так же как мы можем делать с обычной библиотекой.

Для Nemerle 1 создать такой враппер возможно не очень просто.
Возможно стоит исходить из более реального кода, там уже будет видно.

Eugeniy комментирует...

>>> Так в этом и вся проблема. Сейчас мне my_own_using проще и понятнее. Через 3 года мне уже не так проще, и не так понятно.

Если я через 3 года вернусь к своему старому проекту, то мне точно также не будут понятны 90% моего кода и 90% библиотек, которые использовались в этом моем коде (и которые я больше не применял). И мне придется читать документацию (если я ее написал 3 года назад :) ), читать исходники и разбираться что к чему. my_own_using займет доли процента от всего этого времени.

>> А лет через 7 вообще приходится все это выбрасывать. Тогда как "топорный" код хоть и требует больших усилий по первоначальному написанию, зато потом обходится дешевле.

Любой код рано или поздно придется выбрасывать и переписывать с нуля, используя накопленный опыт и современные инструменты. 7 лет не так уж и мало :)

Если my_own_using сэкономил мне несколько тысяч строк кода, то это уже оправдывает его применение...

>> Во-вторых, в ООП библиотеках есть возможность для маневра за счет наследования и переопределения виртуальных функций.

Это зависит от степени корявости. Хорошо написанные библиотеку/dsl улучшить можно, плохо написанные - проблематично или невозможно

>> В-третьих, вы можете написать свой враппер над libcurl и использовать его параллельно с чужим враппером в том же самом коде. Не думая о совместимости синтаксисов и разнесения разных фрагментов по разным файлам.

Не имел дела с немерле, однако немного пишу на скале. Там нет макросов, но язык позволяет делать например такое:


actor {
var sum = 0
loop {
receive {
case Data(bytes) => sum += hash(bytes)
case GetSum(requester) => requester ! sum
}
}
}


Эта штука из стандартной библиотеки и написана на самой скале. Если мне понадобится добавить свои собственные "акторы", то не будет никаких проблем совместить их в одном файле. Вероятно такие способы есть и в немерле.

В моем рабочем проекте на С++ используется пара DSL. Один полностью на макросах, второй на макросах и внешнем генераторе. Использую их уже года 3. Они существенно уменьшают объем кода и делают код яснее. Кроме того, я могу поменять реализацию dsl и не переделывать исходники (что я пару раз делал). Да, если на мой проект придет Вася, ему придется почитать доку. Я честно говоря не вижу в этом особой проблемы...

eao197 комментирует...

@Eugeniy:

>Это зависит от степени корявости. Хорошо написанные библиотеку/dsl улучшить можно, плохо написанные - проблематично или невозможно

Вот на счет расширения даже хорошо написанного DSL есть у меня некоторые сомнения. Доводилось делать что-то вроде IDL на yacc-е и со времнем расширять IDL. Даже с yacc-ом это было затруднительно.

>Не имел дела с немерле, однако немного пишу на скале. Там нет макросов, но язык позволяет делать например такое

Вот! Вот! Вот и подошли к логичному итогу. Есть Ruby и Python, на которых DSL-и создаются без изменения синтаксиса (но, зачастую, за счет eval и особенностей динамической типизаци). Есть Scala, в которой можно делать DSL-и без изменения синтаксиса. Если Haskell, в конце-концов.

А вот изменение синтаксиса, как в Nemerle -- это уже черезчур. Аналогичного эффекта можно достичь и более простыми методами.

eao197 комментирует...

@NN:

Предлагаю завязывать. Спасибо за участие в теме. Было ОЧЕНЬ приятно пообщаться с Nemerle-истом, который признает возможные проблемы. В свое время на RSDN-е этого не хватало и, имхо, именно это отвратило от языка некоторый процент потенциальных пользователей.

Вашу точку зрения я понял. Пока остаюсь при своем мнении, т.к. для переубеждения нужно подождать результатов широкого внедрения Nemerle в массы.

NN​ комментирует...

Спасибо и вам за дискуссию.
Надеюсь ответил на интересующие вас вопросы.

У меня есть большие сомнения, что синтаксические макросы будут лепить направо и налево даже при большом использовании Nemerle. Обычно макроаттрибут представляет более рациональное решение.

Хотя подозреваю, что скорее всего будут проблемы другого плана, а проблемы коллизии синтаксических макросов будут далеко в стороне :)

eao197 комментирует...

@NN:

>У меня есть большие сомнения, что синтаксические макросы будут лепить направо и налево даже при большом использовании Nemerle.

Попадись мне Nemerle лет десять, а то и пять лет назад (не говоря уже про пятнадцать), я бы задействовал изменение синтаксиса на полную катушку ;)

Вообще, многие сомнения которые я высказываю -- это следствие набитых собственных шишек на собственных частных решениях и велосипедов.

Unknown комментирует...

Ну вот... опоздал :(

Дополню лишь, что Тим Петерс (весьма уважаемый python-гуру) как-то сказал (не дословно, но близко к тексту), что "если вы не понимаете, зачем вам нужно метапрограммирование, значит оно вам, на самом деле, пока не нужно".

NN​ комментирует...

Попадись мне Nemerle лет десять, а то и пять лет назад (не говоря уже про пятнадцать), я бы задействовал изменение синтаксиса на полную катушку ;)

Значит он попался во время :)

Все же есть порядок решений.
1. В виде обычной библиотеки. (Классы, методы и прочее)
2. В виде метааттибута.
3. Небольшое синтаксическое расширение. Типа linq <# #>.
4. Глобальное синтаксическое расширение, там операции &&, ||.

Ежели в Java/C# большинство задач решаются на 1-й стадии. Значит так и в Nemerle.
А на следующие стадии ведь переходим только после того как видим невозможность решения в обычных рамках.

Как любая задача, нужен правильный подход.
Для простой конкатенации строк не будем ведь использовать boost::format. :)


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

Вспомни макросы С. В С их используют много, но в С++ гораздо меньше, хотя можно было их использовать и в С++. Почему так ? Потому что опыт показал, что гораздо лучше использовать другие средства, и только когда это не помогает , прибегаем к грубой силе.

P.S.
На самом деле есть кто применяет макросы в С++ не по делу.
Все же мне на практике чаще всего попадаются простые макросы для констант, а не серьезные навороты.

P.P.S.
Где тут смайлик пиво ? :)

eao197 комментирует...

@NN:

>Полностью согласен с тем, что можно безумно использовать фичи и фишки языка. Однако я уверен, что найдется тот самый компромисс и люди будут применять все по делу.

Вспомни макросы С. В С их используют много, но в С++ гораздо меньше, хотя можно было их использовать и в С++. Почему так ? Потому что опыт показал, что гораздо лучше использовать другие средства, и только когда это не помогает , прибегаем к грубой силе.


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

В C++ совсем недавно был modern C++ overdesign :) Так что с синтаксическими макросами нужно ожидать overuse, по другому не бывает :)

>Где тут смайлик пиво ?

Можно просто :beer: -- я пойму :)

NN​ комментирует...

В C++ совсем недавно был modern C++ overdesign :) Так что с синтаксическими макросами нужно ожидать overuse, по другому не бывает :)

Будем надеется на лучшее как обычно.

А если будет, то пройдет.
Заодно и опыта прибавит.

Поживем увидим.

eao197 комментирует...

@NN:

>Поживем увидим.

Угу.

Но боюсь, мне нужно еще раз подчернуть цель моего поста. Я вовсе не пытаюсь опорочить Nemerle или доказать, что у него нет будущего. Имхо, слишком рьяные его проповедники делают это убедительнее :(

Но, на мой взгляд, при рекламировании Nemerle как языка для решения прикладных (а не околосистемных, вроде парсеров или утилитных библиотек) задач не стоит позиционировать возможность изменения синтаксиса как большое достоинство. Это слишком уж спорный момент.

Рекламировать его стоит за счет других вещей, которых нет в C#.

Джереми Младший Кролик комментирует...

>> библиотеки развивать и сопровождать проще, чем DSL-и. Lisp или Forth, которые как раз провоцируют на использование DSL-ей, сейчас нужно с микроскопом искать.

Есть такая платформа - Wolfram Mathematica. Фактически, это более читаемый диалект ЛИСПа. Я бы не сказал, что Math нужно с микроскопом искать. На ней выполнено несколько серьёзных проектов, типа той же известной Wolfram Alpha. Ею пользуются в CERN'е и там постепенно переходят на неё, как на стандарт.

eao197 комментирует...

@Джереми Младший Кролик

>Я бы не сказал, что Math нужно с микроскопом искать. На ней выполнено несколько серьёзных проектов, типа той же известной Wolfram Alpha.

Если заглянуть в дистрибутивы emacs или AutoCad, то можно найти большое количество кода на Lisp-е.

Но это вовсе не доказывает, что Lisp сейчас повсеместно используется для разработки ПО.

Аналогично и с Matematica.

Но намного интереснее, а выбрали бы сейчас в Matematica Lisp за основу своего языка программирования (впрочем, с Matematica не работал, поэтому доверяю вашей информации о Lisp-оподобии тамошнего языка).

jazzer комментирует...

Я на Mathematica делал свой диплом/диссер.
Если честно, ничего особенно лиспового я в ней не увидел, может, конечно, что-то изменилось за 10 лет...
Но с функциональным программированием, паттер-матчингом и т.п. я познакомился именно в Mathematica, году так в 96-м.

Джереми Младший Кролик комментирует...

Вообще Math - мульти-парадигменный язык, сочетающий в себе идеи Пролога, Лиспа, APL и кучи других.

Основной механизм языка Лисп — инкапсулированная в список определяющая голова списка и подключённый к ней хвост списка, который рекурсивно также может быть списком. В Math работает аналогичный принцип.

Джереми Младший Кролик комментирует...
Этот комментарий был удален автором.
Джереми Младший Кролик комментирует...

Про повсеместное использование Math никто не говорит. на Math прогает достаточно большая часть научного комьюнити и на ней написано несколько серьёзных проектов.

Выбрали бы её сейчас? Думаю, пока нет, не выбрали бы. Ибо это потребует пересмотреть ряд подходов в современном программировании. Народ спорит с тезисом "нужен язык с макросами, типа Немерловских". О каком выборе Math как языка тогда идёт речь? Всякие фундаментальные решения из Math, типа верхних и нижних значений, просто взорвут оспаривающей стороне мозг. Ещё пройдёт куча лет споров, пока подобные решения наконец-таки признают.

eao197 комментирует...

@Джереми Младший Кролик:

>Основной механизм языка Лисп — инкапсулированная в список определяющая голова списка и подключённый к ней хвост списка, который рекурсивно также может быть списком.

Имхо, это определение необходимое, но явно недостаточное для идентификации Lisp-а. Поскольку я, например, не могу понять, чем тогда Lisp отличается от Пролога. В Прологе же точно так же.

>Про повсеместное использование Math никто не говорит. на Math прогает достаточно большая часть научного комьюнити и на ней написано несколько серьёзных проектов.

Собственно я о том, что Math не совсем корректный пример. Если кому-то нужно сделать расчет, с которым легко справляется Math, то у человека нет выбора -- придется писать на языке Math. Точно так же, если кому-то нужно расширить emacs, то придется брать elisp.

Джереми Младший Кролик комментирует...

>> Поскольку я, например, не могу понять, чем тогда Lisp отличается от Пролога.

В Прологе сахар ":-" имеет полную форму?

>> Если кому-то нужно сделать расчет, с которым легко справляется Math, то у человека нет выбора -- придется писать на языке Math.

Выбор есть. Ибо есть другие серьёзные пакеты: например, Maple (который находится в дикой конкуренции с Math). Некоторые из них справляются с узкоспециализированными задачами гораздо лучше: например, FORM.

Вы воспринимаете Math только как математический пакет?
На нём кодогенераторы пишут. Интеллектуальный поисковик создали.
Я лично писал администраторские скрипты.
И т.д.

eao197 комментирует...

@Джереми Младший Кролик

>В Прологе сахар ":-" имеет полную форму?

Полная форма -- это что?

В любом случае, обработка данных в Пролог строится таким образом, как вы описали: инкапсулированная в список определяющая голова списка и подключённый к ней хвост списка, который рекурсивно также может быть списком -- посредством рекурсии контейнер делится на голову и (возможно пустой) хвост.

>Выбор есть. Ибо есть другие серьёзные пакеты: например, Maple (который находится в дикой конкуренции с Math).

Это тоже самое, что emacs против vim. Можно выбрать либо то, либо другое, либо еще что-то. Но если выбор остановился на emacs, то остается только elisp. Аналогично и с Mathematica.

>Я лично писал администраторские скрипты.

Я подозревал, что афоризм "забивать гвозди микроскопом" появился не на пустом месте.

Джереми Младший Кролик комментирует...

>> Полная форма -- это что?

Это именно то, что Вы же сами и процитировали: форма в виде "голова - хвост".
Пример, типа:
[...]
f(n) :- f(n-1) + f(n-2).
[...]
так не выглядит.
В Math подобное
[...]
x -> y
[...]
может быть представлено в полной форме:
[...]
Rule[x,y]
[...]
c чем можно работать, как с данными.

>> Это тоже самое, что emacs против vim. Можно выбрать либо то, либо другое, либо еще что-то. Но если выбор остановился на emacs, то остается только elisp. Аналогично и с Mathematica.

Я человек простой, можно сказать, крестьянский. :) У меня с аналогиями плохо. Чего конкретно, по-Вашему мнению, не хватает в Mathematica, что она становится аналогичной Emacs с ELisp?

Возможности писать на другом языке и при этом использовать библиотеки Math? Пожалуйста - пишите, используйте.


Вы сначала сформулировали тезис, что, мол, проекты на Лиспах нужно искать под микроскопом. Вот тот же упомянутый Wolfram Alpha нужно под микроскопом искать? Или какой Вам масштаб проектов нужен, чтобы убедить, что на этих Лиспах отлично создаются сложные проекты?

Джереми Младший Кролик комментирует...

>> Я подозревал, что афоризм "забивать гвозди микроскопом" появился не на пустом месте.

Вы никогда, я полагаю, не писали на Math эти скрипты, но уверенно выдали намёк, что, мол, это подобно забиванию гвоздей микроскопом.

eao197 комментирует...

@Джереми Младший Кролик

>может быть представлено в полной форме:
[...]
Rule[x,y]
[...]
c чем можно работать, как с данными.


Причина нашего непонимания стала ясна. В утверждении "инкапсулированная в список определяющая голова списка и подключённый к ней хвост списка, который рекурсивно также может быть списком." вы, я думаю, подразумевали и возможность представления кода как данных. Мне же представлялось, что речь идет только о данных, не о коде. Посему я и посчитал данное утверждение недостаточным для идентификации именно Лиспа.

>Чего конкретно, по-Вашему мнению, не хватает в Mathematica, что она становится аналогичной Emacs с ELisp?

Изначальной направленности на нишу универсального языка программирования. Mathematica, как и emacs -- это пакет для определенных задач. Но благодаря встроенному в него языку перешагнувшему изначально отведенные ему рамки.

eao197 комментирует...

>Вы сначала сформулировали тезис, что, мол, проекты на Лиспах нужно искать под микроскопом. Вот тот же упомянутый Wolfram Alpha нужно под микроскопом искать? Или какой Вам масштаб проектов нужен, чтобы убедить, что на этих Лиспах отлично создаются сложные проекты?

Я сегодня на SourceForge искал программку для построения турнирных сеток спортивных соревнований. Просмотрел несколько десятков из пары сотен проектов, в описании которых был нужный набор ключевых слов. Спектр языков программирования в этих проектах был самый разнообразный -- в основном Java, есть C++, Perl, PHP, даже JavaScript. На Lisp-е или Mathematica не было ни одного.

Единственный проектик, который хоть как-то был привязан к Lisp-у (точнее даже к Scheme) оказался libtour позаброшенный автором в уже далеком 2005 году.

Так что человеку далекому и от Lisp-а, и от Wolfram Mathematica проекты на этих языках нужно еще поискать. А что таковые есть, так я в этом не сомневался.

eao197 комментирует...

>Вы никогда, я полагаю, не писали на Math эти скрипты, но уверенно выдали намёк, что, мол, это подобно забиванию гвоздей микроскопом.

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

Сюрреалистично как-то выходит :)

Джереми Младший Кролик комментирует...

>> И без проблем поделитесь с админом этим скриптиком. Только вот ему нужно будет себе Math поставить.

Math, скорее всего, ставить не понадобиться. Достаточно будет установить Wolfram CDF Player.

Если речь идёт действительно про скриптик (маленький такой), то можно скомпилировать его и отдать полученное standalone-приложение админу.

Можно дать погонять скриптик через удалённое ядро Math.

Джереми Младший Кролик комментирует...

>> Так что человеку далекому и от Lisp-а, и от Wolfram Mathematica проекты на этих языках нужно еще поискать.

Лиспы не слишком популярны? Этот очевидный факт Вы хотели озвучить?

Зачем человеку искать проект именно на языке Math? У нас же, вроде, есть модная идея о платформе, под которую создана некоторая программа, написанная в свою очередь на некотором языке и дорабатываемая на том же или любом другом? Mathematica - одна из таких платформ. Ко всему, она дружественна к .Net- и Java-платформе.

eao197 комментирует...

>Лиспы не слишком популярны? Этот очевидный факт Вы хотели озвучить?

Для любителей Лиспа (а среди них на профильных форумах как раз очень много защитников метапрограммирования) этот факт не является очевидным, имхо.

>У нас же, вроде, есть модная идея о платформе, под которую создана некоторая программа, написанная в свою очередь на некотором языке и дорабатываемая на том же или любом другом?

Я не являюсь сторонником этой идеи. На мой взгляд, если есть софт X написанный на языке N, то с высокой степенью вероятности дорабатываться он будет именно на языке N. Посему чем проще будет язык N позволять входить новым людям в проект, тем лучше.

А метапрограммирование этому не сильно способствует. Следствием чего и является очевидный факт малой популярности Лиспа.

Джереми Младший Кролик комментирует...

@Евгений Охотников

Зачем вводить такие ограничения? Вот есть Ruby. И есть Python. Допустим, я знаю последний, нашёл клёвый пакет, написанный, на первом. Хочу на его базе создать более продвинутый. Мне учить Ruby, получается?

Вторая ситуация. Я разработал некий язык. Мне под него и библиотеки писать? Без библиотек кто ж им пользоваться-то будет?

>> А метапрограммирование этому не сильно способствует.

Вы какой-нибудь убедительный пример приведите...

eao197 комментирует...

@Джереми Младший Кролик:

>Хочу на его базе создать более продвинутый. Мне учить Ruby, получается?

Не понимаю, что значит "создать более продвинутый на базе". Если речь идет о создании нашлепки Y над библиотекой X без необходимости переделки внутренностей X, то это совсем другая опера.

Большинство задач по сопровождению сводится к другим формулировкам. Вот из моей практики, вчерашнее. Есть некая самодостаточная программа, совсем не reusable-компонент. К ней выдвигаются новые требования: "1. Cделать дополнительный опциональный параметр, указывающий имя файла лога - чтобы можно бвло из одного места с одними конфигами запускать несколько импортов и не путаться в результатах. 2. Выводить в лог первое и последнее время операции из записываемой пачки данных. Записал в лог первое время пачки, записал в базу пачку, записал последнее время."

В таких случаях нужно править исходники программы. И делать это придется на том же самом языке.

>Вторая ситуация. Я разработал некий язык. Мне под него и библиотеки писать? Без библиотек кто ж им пользоваться-то будет?

Таки да. Либо делаете язык для уже существующей платформы (.NET, JVM, что-то еще), либо снабжаете его своими библиотеками. Так делают разработчики D, Go, OOC и т.д.

>Вы какой-нибудь убедительный пример приведите...

Убедительный пример чего? Документально зафиксированный пример мата нового разработчика, который клянет маму своего предшественника, насовавшего в C++ный код макросов и шаблонов?

Или непопулярность Lisp-а все-таки уже само по себе хорошее доказательство?