Почему макросы Nemerle не являются злом?
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.04.11 02:14
Оценка: 69 (8)
Среди тех кто не использовал макросы Nemerle на практике есть те кто верит и распространяет одни миф. Звучит он так «Введение в язык средств метапрограммирования опасно. В конечном итоге приведет к адовому кол-ву несовместимых языков » (http://www.rsdn.ru/forum/philosophy/4246218.aspx
Автор: Lloyd
Дата: 23.04.11
).
Оставшаяся часть данного сообщения будет посвящена развенчанию данного мифа. Я вывел ее в отдельную тему, чтобы она не потерялась в потоках флуда развившегося в указанной теме. Ну, и чтобы выделить дискуссию и направить ее по одному руслу.
Для начала некоторая информация о макросах. Без нее трудно понять суть умозаключений последующих ниже.

Макросы располагаются в отдельных сборках

Макрос – это плагин к компилятору. В Nemerle макрос это такой же код как и любой остальной, а значит перед исполнением его нужно скомпилировать и поместить в исполняемую сборку.
Для того чтобы использовать макрос в некотором проекте сначала нужно подключить (к этому проекту) сборку в которой он описан.
Таким образом макрос не может случайно или незаметно появиться в программе.
Стандартные макросы расположены в стандартной макро-сборке Nemerle.Macros.dll идущей в поставке компилятора. По умолчанию она подключается к любому проекту Nemerle. Но ее загрузку можно предотвратить. В этом случае проек будет использовать так называемый базовый Nemerle.
Пользоваться базовым Nemerle очень не просто. То что большинство Nemerle-программистов понимают под Nemerle включает в себя и набор стандартных макросов. Так, например, в базовом Nemerle нет не только ни одного вида цикла, но даже операторов if/else и даже операторов || и &&. По этому обычно проект использует Nemerle.Macros.dll или ее замену (если есть необходимость сильно переделать расширенную часть языка).

Макросы располагаются в пространствах имен

Как и обычные типы макросы располагаются в некотором пространстве имен. По этому перед тем как использовать макросы (если он не объявлен в глобальном пространстве имен) пространство имен в котором он объявлен необходимо открыть с помощью директивы using.
В стандартной библиотеке есть набор макросов которые находятся в глобальном пространстве имен и стало быть доступны без предварительного открытия. Это в основном макросы реализующие стандартные операторы языка (for, foreach, if/else, ||, &&, += и т.п.).

Метапрограммирование и макросы != расширение синтаксиса

Надо отметить то факт, что не всякое метапрограммирование и макросы приводят к расширению синтаксиса. Так в Nemerle поддерживаются макросы в виде атрибутов (аналогичных custom attributes в C#, но приводящим не к генерации метаданных, а к вызову некоторого компиляторного плагина) и в виде вызова функций (обращение к макросу заменяется на результат возвращаемый макросом во время компиляции).
Указанные виды макросов не расширяют синтаксис языка и соответствуют всем правилам разрешения неоднозначностей (аналогичным таковым в C#). Например, вы можете задать полностью квалифицированное имя при обращении к макросу. Так, например, вместо:

using MyMacros;
...
MyMacro(42);

Можно написать:

MyMacros.MyMacro(42);

Неоднозначности

Неоднозначности в программах возникают отнюдь не только при использовании макросов. Так в языках вроде C#, VB (да и в Nemerle) легко написать библиотеку которая будет конфликтовать с другой.
Например, если мы опишем два метода расширения в двух разных классах (пример на C#):

Namespase Ns1
{
  public static class A
  {
    public static class string ExtentionMethod(this string sourse) { return "*" + sourse + "*"; }
  }
}

Namespase Ns2
{
  public static class B
  {
    public static class string ExtentionMethod(this string sourse) { return "!" + sourse + "!"; }
  }
}

И попытаемся обратиться к ним:

using Ns1;
using Ns2;

public static class Program
{
  static class void Main()
  {
    "test".ExtentionMethod()
  }
}

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

Ns2.A.ExtentionMethod( "test");

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

Неоднозначности и макросы

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

«Адово» количество несовместимых «языков»

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

Учитывая, что базовый язык и стандартная библиотека развиваются по принципам похожим для развитие монолитных языков – новые возможности попадают в язык не сразу, а после тщательного обдумывания, проектирования и тестирования, то бояться за то что «зоопарк» случится в стандартной библиотеке макросов не стоит.
Остается вопрос конфликта между библиотеками макросов третьих лиц и библиотеками создаваемыми в рамках проекта разработки ПО в котором применяется Nemerle.
Несомненно конфликты между такими библиотеками возможны. Но они ничем не отличаются от конфликтов обычных библиотек. Разработчики вольны выбирать макро-библиотеки которые они хотят использовать и использовать их там где нужно (в тех файлах проекта где в них есть необходимость.

Отличия от монолитных языков

В отличии от монолитных языков где синтаксис появившись единожды уже не может быть отброшен, и в которых синтаксис «виден» во всех файлах проектов, в языках поддерживающих макросы введение нового синтаксиса не влечет столь серьезных и не обратимых последствий.
Так в разных фалах одного и того же проекта можно использоваться макросы конфликтующие друг с другом синтаксически. Более тог в разных файлах можно использовать даже разные версии одного и того же макроса (если в это есть необходимость).
Кроме того в любой момент вы вольны отказаться от использования макроса или все макро-сборки. Для этого достаточно будет убрать открытие соответствующих имен и/или отключить макро-сборку содержащую эти макросы.

Жизнь без оков

Как не странно макросы снимают кучу проблем с авторов языка. Новая возможность может быть легко реализована в виде отдельной сборку и без долгого тестирования выложена на суд пользователей. Если пользователи не выразят негативного отношения к новинке, можно перенести макрос в стандартную библиотеку. В прочем можно оставить новшество в отдельной библиотеке и просто включить ее в состав инсталлятора Nemerle.
Тот же подход можно использовать и в рамках больших проектов. Управляющими проекта может быть создана стандартная библиотека макросов проекта в которую после предварительного тестирования будут включаться макросы третьих лиц или самописные макросы необходимые для проекта.
Другие макро-библиотеки можно попросту запретить использовать (или создать список допустимых к использованию макро-библиотек).

Заключение

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

Конечно среди макросов могут быть конфликты. Но эти конфликты не фатальных. Ими можно управлять, а от неудачного макроса (или макро-библиотеки) можно избавиться точно так же как от неудачной библиотеки.
Нет никакой разницы между библиотеками функций и макро-библиотеками. Точнее вся разница заключается только в том когда и где загружается данная библиотека. Макро-библиотека загружается на исполнение в рамках процесса компиляции в то время как обычная библиотека загружается компилятором для чтения метаданных, а на исполнение она загружается при старте приложения.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: Почему макросы Nemerle не являются злом?
От: Lloyd Россия  
Дата: 24.04.11 05:18
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Метапрограммирование и макросы != расширение синтаксиса

VD>Надо отметить то факт, что не всякое метапрограммирование и макросы приводят к расширению синтаксиса. Так в Nemerle поддерживаются макросы в виде атрибутов (аналогичных custom attributes в C#, но приводящим не к генерации метаданных, а к вызову некоторого компиляторного плагина) и в виде вызова функций (обращение к макросу заменяется на результат возвращаемый макросом во время компиляции).

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

VD>Неоднозначности и макросы


VD>Но что же делать с макросами имеющими синтаксис конфликтующий с другими синтаксическими макросами?

VD>Все очень просто. Если такое случилось, то один из макросов можно вызвать используя нотацию вызова фукнции. При этом вы не сможете воспользоваться синтаксическим расширением, но сможете квалифицировать имя макроса избежав тем самым конфликта имен или синтаксиса.

Можно подробнее? Например, как используя "нотацию вызова фукнции" сконструировать linq-запрос? Или вызвать while, который вроде как тоже реализован макросом.

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

VD>Таким образом конфликты имен макросов решаются точно так же как и для обычных типов и методов.
VD> «Адово» количество несовместимых «языков»
VD>Теперь перейдем собственно к основному мифу.
VD>К данному моменту вы должны понимать, что создать полностью несовместимые «языки» вы не в состоянии. Вопрос разрешения конфликтов может решить любую несовместимость.

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

VD>Учитывая, что базовый язык и стандартная библиотека развиваются по принципам похожим для развитие монолитных языков – новые возможности попадают в язык не сразу, а после тщательного обдумывания, проектирования и тестирования, то бояться за то что «зоопарк» случится в стандартной библиотеке макросов не стоит.


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

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

VD>Несомненно конфликты между такими библиотеками возможны. Но они ничем не отличаются от конфликтов обычных библиотек.

Как разрешать конфликты библиотек — понятно. А вот как разрешать конфликты синтаксиса?

VD>Разработчики вольны выбирать макро-библиотеки которые они хотят использовать и использовать их там где нужно (в тех файлах проекта где в них есть необходимость.


Это нужно понимать как рекомендацию не использовать конфликтующие синтаксические макросы? Или все-таки есть средства разрешения конфликтов?

VD>Отличия от монолитных языков


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


Я бы не стал приписывать возможность отключения фич исключительно макро-языкам. В том же питоне и хаскеле тоже можно влючать/выключать експериментальные фичи, хотя они и являются "монолитными языками".

VD>Так в разных фалах одного и того же проекта можно использоваться макросы конфликтующие друг с другом синтаксически. Более тог в разных файлах можно использовать даже разные версии одного и того же макроса (если в это есть необходимость).


Это и есть то, что я назвал адовыми несовместимостями.

VD>Кроме того в любой момент вы вольны отказаться от использования макроса или все макро-сборки. Для этого достаточно будет убрать открытие соответствующих имен и/или отключить макро-сборку содержащую эти макросы.


VD>Заключение


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


Пока нельзя.
Re[2]: Почему макросы Nemerle не являются злом?
От: Ziaw Россия  
Дата: 24.04.11 05:43
Оценка: 4 (2) +2
Здравствуйте, Lloyd, Вы писали:

L>Можно подробнее? Например, как используя "нотацию вызова фукнции" сконструировать linq-запрос? Или вызвать while, который вроде как тоже реализован макросом.


Nemerle.Linq.LinqMacro(<# from i in Enumerable.Range(0, 10) select i #>)
Nemerle.Core.while(a > 10, { a ++; });


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


Поинт в том, что использование разных сторонних разработок способно внести неоднозначности в код проекта вне зависимости от того, используют ли они метапрограммирование. На практике я очень редко встречал проблемы с этим. Обычно решается соглашением, что один из неймспейсов во всем проекте задается как как using Xxx=SomeLib.Conflicting.Namespace.

Если у тебя они были, ты расскажи.

L>Как разрешать конфликты библиотек — понятно. А вот как разрешать конфликты синтаксиса?


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

VD>>Так в разных фалах одного и того же проекта можно использоваться макросы конфликтующие друг с другом синтаксически. Более тог в разных файлах можно использовать даже разные версии одного и того же макроса (если в это есть необходимость).


L>Это и есть то, что я назвал адовыми несовместимостями.


Дык, сдуру можно и х*р сломать, однако от проблемы хрупкости этого органа человечество не вымерло.
Re[2]: Почему макросы Nemerle не являются злом?
От: hardcase Пират http://nemerle.org
Дата: 24.04.11 07:11
Оценка:
Здравствуйте, Lloyd, Вы писали:

VD>>Но что же делать с макросами имеющими синтаксис конфликтующий с другими синтаксическими макросами?

VD>>Все очень просто. Если такое случилось, то один из макросов можно вызвать используя нотацию вызова фукнции. При этом вы не сможете воспользоваться синтаксическим расширением, но сможете квалифицировать имя макроса избежав тем самым конфликта имен или синтаксиса.

L>Можно подробнее? Например, как используя "нотацию вызова фукнции" сконструировать linq-запрос? Или вызвать while, который вроде как тоже реализован макросом.


Я иногда использую функциональную запись if-else для записи коротких однострочных условий:
@if(x > y, x, y)
/* иЗвиНите зА неРовнЫй поЧерК */
Re[3]: Почему макросы Nemerle не являются злом?
От: Курилка Россия http://kirya.narod.ru/
Дата: 24.04.11 07:21
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Здравствуйте, Lloyd, Вы писали:


L>>Можно подробнее? Например, как используя "нотацию вызова фукнции" сконструировать linq-запрос? Или вызвать while, который вроде как тоже реализован макросом.


H>Я иногда использую функциональную запись if-else для записи коротких однострочных условий:

H>
H>@if(x > y, x, y)
H>


if не является выражением? Т.е. нельзя как в скале:

if (x > y) x else y

Re[4]: Почему макросы Nemerle не являются злом?
От: hardcase Пират http://nemerle.org
Дата: 24.04.11 07:27
Оценка:
Здравствуйте, Курилка, Вы писали:

К>Здравствуйте, hardcase, Вы писали:


H>>Здравствуйте, Lloyd, Вы писали:


L>>>Можно подробнее? Например, как используя "нотацию вызова фукнции" сконструировать linq-запрос? Или вызвать while, который вроде как тоже реализован макросом.


H>>Я иногда использую функциональную запись if-else для записи коротких однострочных условий:

H>>
H>>@if(x > y, x, y)
H>>


К>if не является выражением? Т.е. нельзя как в скале:


К>

К>if (x > y) x else y


Является
Но заметь, приведенный мною код чуточку короче чем твой Такой случай использования иногда (совсем не часто) удобен для передачи аргументов:
foo(a, b, @if(x > y, x, y), c)

что совершенно эквивалентно:
foo(a, b, if(x > y) x else y, c)

что совершенно эквивалентно:
foo(a, b, match(x > y) { true => x | _ => y }, c)
/* иЗвиНите зА неРовнЫй поЧерК */
Re[5]: Почему макросы Nemerle не являются злом?
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 24.04.11 07:39
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Но заметь, приведенный мною код чуточку короче чем твой Такой случай использования иногда (совсем не часто) удобен для передачи аргументов:

H>
H>foo(a, b, @if(x > y, x, y), c)
H>

А порядок вычислений для веток тут какой? Ленивый или энерчиный?

H>что совершенно эквивалентно:

H>
H>foo(a, b, if(x > y) x else y, c)
H>

H>что совершенно эквивалентно:
H>
H>foo(a, b, match(x > y) { true => x | _ => y }, c)
H>
Re[5]: Почему макросы Nemerle не являются злом?
От: Курилка Россия http://kirya.narod.ru/
Дата: 24.04.11 07:44
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Но заметь, приведенный мною код чуточку короче чем твой Такой случай использования иногда (совсем не часто) удобен для передачи аргументов:

H>
[cut]


Борешься с синтаксическим оверхэдом?
Re[6]: Почему макросы Nemerle не являются злом?
От: hardcase Пират http://nemerle.org
Дата: 24.04.11 08:20
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Здравствуйте, hardcase, Вы писали:


H>>Но заметь, приведенный мною код чуточку короче чем твой Такой случай использования иногда (совсем не часто) удобен для передачи аргументов:

H>>
H>>foo(a, b, @if(x > y, x, y), c)
H>>

G>А порядок вычислений для веток тут какой? Ленивый или энерчиный?

Этот @if не функция — это вызов синтаксического макроса "без синтаксиса"; слова "совершенно эквивалентно" нужно понимать буквально: все три примера компилируются в идентичный машинный код. Хотя Nemerle — энергичный язык, в данном случае вычисления ленивые (потому что это тот же самый if-else).
/* иЗвиНите зА неРовнЫй поЧерК */
Re[6]: Почему макросы Nemerle не являются злом?
От: hardcase Пират http://nemerle.org
Дата: 24.04.11 08:21
Оценка:
Здравствуйте, Курилка, Вы писали:

К>Борешься с синтаксическим оверхэдом?


Нет, я за читабельность ратую.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[7]: Почему макросы Nemerle не являются злом?
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 24.04.11 08:49
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Здравствуйте, gandjustas, Вы писали:


G>>Здравствуйте, hardcase, Вы писали:


H>>>Но заметь, приведенный мною код чуточку короче чем твой Такой случай использования иногда (совсем не часто) удобен для передачи аргументов:

H>>>
H>>>foo(a, b, @if(x > y, x, y), c)
H>>>

G>>А порядок вычислений для веток тут какой? Ленивый или энерчиный?

H>Этот @if не функция — это вызов синтаксического макроса "без синтаксиса"; слова "совершенно эквивалентно" нужно понимать буквально: все три примера компилируются в идентичный машинный код. Хотя Nemerle — энергичный язык, в данном случае вычисления ленивые (потому что это тот же самый if-else).


то есть можно написать макрос как функцию, которая будет вести себя лениво, но пользователь об этом не узнает?
Re[7]: Почему макросы Nemerle не являются злом?
От: Курилка Россия http://kirya.narod.ru/
Дата: 24.04.11 08:52
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Здравствуйте, Курилка, Вы писали:


К>>Борешься с синтаксическим оверхэдом?


H>Нет, я за читабельность ратую.


Лично мне кажется твой вариант менее читабельным.
Re[8]: Почему макросы Nemerle не являются злом?
От: hardcase Пират http://nemerle.org
Дата: 24.04.11 09:07
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>то есть можно написать макрос как функцию, которая будет вести себя лениво, но пользователь об этом не узнает?


У нас есть макрос lazy.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[8]: Почему макросы Nemerle не являются злом?
От: FR  
Дата: 24.04.11 10:57
Оценка: 9 (1)
Здравствуйте, gandjustas, Вы писали:

H>>Этот @if не функция — это вызов синтаксического макроса "без синтаксиса"; слова "совершенно эквивалентно" нужно понимать буквально: все три примера компилируются в идентичный машинный код. Хотя Nemerle — энергичный язык, в данном случае вычисления ленивые (потому что это тот же самый if-else).


G>то есть можно написать макрос как функцию, которая будет вести себя лениво, но пользователь об этом не узнает?


Если имеешь в виду с ленивыми параметрами то для этого макросы необязательны, например в D они есть http://www.digitalmars.com/d/2.0/lazy-evaluation.html
тот же @if на них вполне реализуется:

import std.stdio;

T my_if(T)(bool Cond, lazy T ExpIf, lazy T ExpElse)
{
if(Cond)
    return ExpIf;
else
    return ExpElse;
}

void main()
{
    my_if(true, writeln("Ok"), writeln("Fail"));
    my_if(false, writeln("Ok"), writeln("Fail"));
    
    T sign(T)(T x)
    {
        return my_if(x < 0, -x, x);
    }
    
    assert(sign(10) == 10);
    assert(sign(-10) == 10);
}
Re[2]: Почему макросы Nemerle не являются злом?
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.04.11 11:51
Оценка: 2 (1)
Здравствуйте, Lloyd, Вы писали:

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


ОК, уже не плохо.

VD>>Неоднозначности и макросы


VD>>Но что же делать с макросами имеющими синтаксис конфликтующий с другими синтаксическими макросами?

VD>>Все очень просто. Если такое случилось, то один из макросов можно вызвать используя нотацию вызова фукнции. При этом вы не сможете воспользоваться синтаксическим расширением, но сможете квалифицировать имя макроса избежав тем самым конфликта имен или синтаксиса.

L>Можно подробнее? Например, как используя "нотацию вызова фукнции" сконструировать linq-запрос? Или вызвать while, который вроде как тоже реализован макросом.


Ну, получить конфликт на текущем синтаксисе linq-запроса практически невозможно. Но в любом случае вместо синтаксиса:
linq запрос

придется использовать:
Nemerle.Linq.LinqMacro(запрос)

или
LinqMacro(запрос)

Тоже самое и с while. Вместо:
while (true)
  DoSome();

можно писать:
Nemerle.Core.@while(true, DoSome());


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


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

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

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

Еще одно заблуждение которое я часто слышал это мнение о том, что для понимания того что делает макрос нужно знать его устройство. Это так же не соответствует действительности. Для понимания нужно знать семантику. А он обычно очевидна.

Кроме того надо вспомнить о том, что не смотря на макросы у нас есть то что называется языком (т.е. базовый язык плюс стандартные макросы). И, естественно, что в коде проекта в большинстве случаев будет встечаться исключительно этот язык. Макросы которые привносят пользователи решают локальные задачи проекта. По сему рассматриваются только в рамках этого проекта.

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

VD>>Учитывая, что базовый язык и стандартная библиотека развиваются по принципам похожим для развитие монолитных языков – новые возможности попадают в язык не сразу, а после тщательного обдумывания, проектирования и тестирования, то бояться за то что «зоопарк» случится в стандартной библиотеке макросов не стоит.


L>Пример шарпа показывает, что от зоопарка и нелогичностей это не спасает. А учитывая гораздо меньшее кол-во ресурсов у команды немерле, то шансы просачивания такого рода фич гораздо выше.


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

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

Если ты не хочешь прибегать к логике, то попробуй просто взглянуть фактам в глаза. Nemerle разрабатывается меньшее время нежели C#, намного меньшими силами, да и компетентность (скилы) этих сил далеко не всегда на уровне. Однако в Немерле, в отличии от C# проблем не наблюдается. Язык получился значительно более стройный нежели C#. Если бы твои домысли были правдой, то это ну никак не могло бы случиться.

Пойми, мы ассимилируем удачные фичи из C# в мгновение ока. То на что МС тратит годы делается на макросах за какие-то жалкие недели (максимум месяцы). Кроме того мы успеваем сделать новые (и весьма мощные) фичи. А ведь наши ресурсы не просто не сопоставимы, а невероятно не сопоставимы. В одной только команде шарпа есть около сорока человек. И это не учитывая того количества людей которое работает над интеграцией к студии и т.п. То есть мы находимся в несравнимо худших условиях, ведь у нас нет ни одного фул-тайм девелопера! Но меж тем мы вполне конкурируем с МС и его C#. Немерл, даже без самопального расширения (просто с имеющимися из коробки фичами) значительно удобнее C#. Скажем асинки только планируются в новой версии C#, а у нас аналог есть уже где-то год. И сделал его не какой-то гуру, а парень что зашел на форум и не осторожно бросил фразу "F# лучше чем Nemerle, так как в нем есть ComputationExpressions". Ему просто ответили, что у нас есть макросы на которых можно сделать и их в том числе. А парень вместо того чтобы усомниться и пойти разводить скепсис взял и сделал. Сделал в процессе изучения языка. И это у него заняло где-то две недели!

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

L>Как разрешать конфликты библиотек — понятно. А вот как разрешать конфликты синтаксиса?


Их никак не разрешить. Но, ты можешь:
1. Использовать в рамках одного проекта конфликтующие макросы, но в разных файлах.
2. Написать макрос-обертку с не конфликтующим синтаксисом.
3. Отказаться от одного из конфликтующих макросов.

Главное, что проблема не зашита в сам язык. Проблему вызывает библиотека! И у нас есть средства устранения проблем такого рода.

На практике же такие конфликты возникают крайне редко. Могу вспомнить только один случай. Конфликт comp async (из ComputationExpressions о которых я говорил выше) и макроса async из concurrency. Но их просто никто не использует совместно, так как это разные идеологии. А раз так, то их пространства имен никогда не открываются в рамках одного файла, и стало быть, не создают проблем.

VD>>Разработчики вольны выбирать макро-библиотеки которые они хотят использовать и использовать их там где нужно (в тех файлах проекта где в них есть необходимость.


L>Это нужно понимать как рекомендацию не использовать конфликтующие синтаксические макросы? Или все-таки есть средства разрешения конфликтов?


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

L>Я бы не стал приписывать возможность отключения фич исключительно макро-языкам. В том же питоне и хаскеле тоже можно влючать/выключать експериментальные фичи, хотя они и являются "монолитными языками".


Значит уже не очень монолитными. Но тут важно понять другое. Язык определяется стандартом или спками. И понятие внести фичу в язык для монолитного языка в первую очередь означает "изменить спеку". Учитывая обратную совместимость обратного пути у этого процесса нет! И именно это делает данный процесс очень ответственным и опасным. В случае же макросов такой ответственности просто нет. Внешние макро-сборки вообще не влияют на сам язык (его спеку). И даже внесение фичи в стандартную макро-библиотеку не делает эту фичу раз и на всегда прикованной к языку. Если выяснится, что фича была неудачная, то в следующей версии языка мы можем просто ввести удачный вариант поместив его в новое пространство имен. А старое просто оставить как есть! А то будут ли пользователи применять новый или старый вариант зависит исключительно от них!

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

VD>>Так в разных фалах одного и того же проекта можно использоваться макросы конфликтующие друг с другом синтаксически. Более тог в разных файлах можно использовать даже разные версии одного и того же макроса (если в это есть необходимость).


L>Это и есть то, что я назвал адовыми несовместимостями.


Где тут несовместимость? На лицо совместимость. Если же ты хочешь указать на то, что делать так нехорошо, то я даже с тобой соглашусь. Точно так же не хорошо в одном проекте применять две версии одной библиотеки. По уму от такого нужно избавляться. Но в жизни бывают разные случаи. И иметь возможность (пусть даже временно) использовать параллельно старый и новый механизм — это огромное преимущество. Это дает возможность проектам эволюционировать.

VD>>Кроме того в любой момент вы вольны отказаться от использования макроса или все макро-сборки. Для этого достаточно будет убрать открытие соответствующих имен и/или отключить макро-сборку содержащую эти макросы.


VD>>Заключение


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


L>Пока нельзя.


Где логика? Ты же программист? Ты не смог предъявить ни одной внятной претензии, но продолжать придерживаться своего явно не верного мнения.

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

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

Синтаксис не вводится от балды. Его вводят только тогда когда он позволяет выразить мысли более ясно. А это означает, что и код твоих программ станет яснее.

Конечно, используя любой инструмент можно наворотить грязи и утонуть в ней. Но это не повод бояться нового. Так как, как и старое, новое позволяет писать не только грязный и плохой код. Более того новое позволяет писать более понятный, и более высокоуровневых код. ЕДСЛ-и вообще путь в будущее. Отрицать этот путь глупо.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Почему макросы Nemerle не являются злом?
От: Lloyd Россия  
Дата: 24.04.11 14:23
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Здравствуйте, Lloyd, Вы писали:


L>>Можно подробнее? Например, как используя "нотацию вызова фукнции" сконструировать linq-запрос? Или вызвать while, который вроде как тоже реализован макросом.


Z>
Z>Nemerle.Linq.LinqMacro(<# from i in Enumerable.Range(0, 10) select i #>)
Z>Nemerle.Core.while(a > 10, { a ++; });
Z>


Спасибо. Второй пример конечно доставляет.

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


Z>Поинт в том, что использование разных сторонних разработок способно внести неоднозначности в код проекта вне зависимости от того, используют ли они метапрограммирование. На практике я очень редко встречал проблемы с этим. Обычно решается соглашением, что один из неймспейсов во всем проекте задается как как using Xxx=SomeLib.Conflicting.Namespace.


Z>Если у тебя они были, ты расскажи.


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

L>>Как разрешать конфликты библиотек — понятно. А вот как разрешать конфликты синтаксиса?


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


Меня не столько несовместимость пугает, а несогласованность языка. Не знаю, как лучше описать. У меня было время, когда я портировал с VB6 проект на шарп, так вот VB оставил очень неприятное впечатление какого-то лоскутного одеяла, не возникает от него ощущения нормального языка. Похожим образот отзываются и о PHP. Страшно представить, во что бы превратился язык, если он будет свободно разрешать менять синтаксис. Каша будет похлеще VB-шной.

VD>>>Так в разных фалах одного и того же проекта можно использоваться макросы конфликтующие друг с другом синтаксически. Более тог в разных файлах можно использовать даже разные версии одного и того же макроса (если в это есть необходимость).


L>>Это и есть то, что я назвал адовыми несовместимостями.


Z>Дык, сдуру можно и х*р сломать, однако от проблемы хрупкости этого органа человечество не вымерло.


Знаешь, то что сегодня кажется нормальным и логичным, завтра обрастает такими деталями, что начинаешь сильно жалеть, что ввязался. Имею такой опыт именно с мета-программированием (генерация кода как текста, не немерле).
Re[4]: Почему макросы Nemerle не являются злом?
От: Ziaw Россия  
Дата: 24.04.11 15:05
Оценка:
Здравствуйте, Lloyd, Вы писали:

Z>>
Z>>Nemerle.Linq.LinqMacro(<# from i in Enumerable.Range(0, 10) select i #>)
Z>>Nemerle.Core.while(a > 10, { a ++; });
Z>>


L>Спасибо. Второй пример конечно доставляет.


Условием? не подумал о нем

Z>>Поинт в том, что использование разных сторонних разработок способно внести неоднозначности в код проекта вне зависимости от того, используют ли они метапрограммирование. На практике я очень редко встречал проблемы с этим. Обычно решается соглашением, что один из неймспейсов во всем проекте задается как как using Xxx=SomeLib.Conflicting.Namespace.


Z>>Если у тебя они были, ты расскажи.


L>С чем именно? С неоднозначности в синтаксисе, я не встречал, т.к. мне не доводилось использовать языки поддердивающие расширение синтаксиса (примеры из статей — не в счет). Неоднозначности в библиотеках разрешаеются легко, тут проблем нет.


Я спрашивал именно про библиотеки.

L>Меня не столько несовместимость пугает, а несогласованность языка. Не знаю, как лучше описать. У меня было время, когда я портировал с VB6 проект на шарп, так вот VB оставил очень неприятное впечатление какого-то лоскутного одеяла, не возникает от него ощущения нормального языка. Похожим образот отзываются и о PHP. Страшно представить, во что бы превратился язык, если он будет свободно разрешать менять синтаксис. Каша будет похлеще VB-шной.


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

L>Знаешь, то что сегодня кажется нормальным и логичным, завтра обрастает такими деталями, что начинаешь сильно жалеть, что ввязался. Имею такой опыт именно с мета-программированием (генерация кода как текста, не немерле).


Генерация больших объемов кода сама по себе достаточно сложная задача. Генерировать его текстом — дополнительно сильно усложнять ее.
Re[4]: Почему макросы Nemerle не являются злом?
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.04.11 23:33
Оценка:
Здравствуйте, Lloyd, Вы писали:

L>Меня не столько несовместимость пугает, а несогласованность языка. Не знаю, как лучше описать. У меня было время, когда я портировал с VB6 проект на шарп, так вот VB оставил очень неприятное впечатление какого-то лоскутного одеяла, не возникает от него ощущения нормального языка. Похожим образот отзываются и о PHP. Страшно представить, во что бы превратился язык, если он будет свободно разрешать менять синтаксис. Каша будет похлеще VB-шной.


VB — это нормальный язык. И писать на нем можно хорошо и чисто. Проблема как всегда в руках. Когда я глядел на код MPF (библиотеки оберток над API студии) я периодически хотел плакать. Даже хотелось создать фонд помощи работникам Майрософт порожденных терминальной стадией ФГМ-а. Но я при этом понимал, что шарп тут не причем. Если бы они писали код даже на Хаскеле, все равно код был бы "таким".

L>Знаешь, то что сегодня кажется нормальным и логичным, завтра обрастает такими деталями, что начинаешь сильно жалеть, что ввязался. Имею такой опыт именно с мета-программированием (генерация кода как текста, не немерле).


Ну, так и не надо проецировать свой неудачный опыт на немерл.

ЗЫ

Я заметил, что многие противники макросов до этого генерили код руками. Может фобии связаны именно с этим?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Почему макросы Nemerle не являются злом?
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.04.11 23:35
Оценка:
Здравствуйте, hardcase, Вы писали:

H>Я иногда использую функциональную запись if-else для записи коротких однострочных условий:

H>
H>@if(x > y, x, y)
H>


О, блин, хитрец!
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[9]: Почему макросы Nemerle не являются злом?
От: VladD2 Российская Империя www.nemerle.org
Дата: 24.04.11 23:39
Оценка:
Здравствуйте, FR, Вы писали:

FR>Если имеешь в виду с ленивыми параметрами то для этого макросы необязательны, например в D они есть http://www.digitalmars.com/d/2.0/lazy-evaluation.html

FR>тот же @if на них вполне реализуется:

Тут нужно еще помнить о производительности. Все же ленивость через lazy обходится дороговато в энергичных (странное слово) языках.

В случае же if-а имеет место выполнение одного из двух выражений. И это "бесплатно".
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.