Сообщений 331    Оценка 416 [+1/-1]         Оценить  
Система Orphus

Судьба новых идей, или почему прогресс идет так медленно

Автор: Чистяков Влад (VladD2)
The RSDN Group

Источник: RSDN Magazine #2-2008
Опубликовано: 27.08.2008
Исправлено: 10.12.2016
Версия текста: 1.0

Вот уже который раз встречаю преинтереснейшую картину. Эта картина настолько задевает меня, что я решил поделиться с вами своими впечатлениями. Картина эта выглядит так. Где-то в глубине народных масс появляется некая неординарная идея. Эта идея теми или иными путями доходит до ушей в Microsoft и представители Microsoft бодрым голосом заявляют, что мол, это идея бредовая/вредная/бесполезная, и вроде бы тихо про нее забывают. В лучшем случае просто не следует никакой реакции. Проходит время, и вдруг появляется массированный пиар этой самой идеи, исходящий из недр Microsoft. Далее начинается массированная поддержка этой идеи в блогах. Через некоторое время появляются слухи о планах по включению этой возможности в один из продуктов Microsoft, и где-то через 1-3 года продукт, реализующий эту возможность, появляется у нас на компьютерах.

Казалось бы все как в той бородатой хохме: «Любая новая идея сначала воспринимается как безумие, потом как интересная, а потом как сама собой разумеющаяся». Что же тут удивительного? А удивительны сроки и усилия, которые тратит на это мировой гигант, и то, как разительно меняется мнение апологетов Microsoft (они всегда следуют указаниям «партии»).

Простой пример. Много лет назад, когда .NET только-только появился, многие задавились вопросом, почему в C# нет позднего связывания (термин скорее из VB, на самом деле речь шла о динамическом вызове методов). Апологеты Microsoft и его представители отвечали, что мол, статически типизированному языку не к лицу динамика. Мол, это приведет к ошибкам, выявляемым только в runtime. На самом деле если вызов по проектному решению должен быть динамическим, то ошибка по-любому появится в runtime. Разница лишь в том, придется ли программисту реализовывать вызова через рефлексию (т.е. городить горы малопонятного кода), или он сможет обойтись одной строкой. Если неким образом выделить динамические блоки кода (наподобие небезопасных - unsafe), то проблем вроде бы возникнуть не должно. Скажу честно, что мне эти проблемы были тогда до лампочки, так как динамика мне не была нужна, и я просто пропустил эти споры мимо ушей. Прошли годы, и я наткнулся на блог Future Focus I: Dynamic Lookup (http://blogs.msdn.com/charlie/archive/2008/01/25/future-focus.aspx), где говорится о Dynamic Language Runtime (DLR), и, в частности, о том, что в будущие версии C# планируется-таки встроить динамические вызовы, обрамив их специальным блоком «dynamic». Вот пример из этого блога (думаю, он очевиден):

      static
      void Main(string[] args)
{
    dynamic
    {
        object myDynamicObject = GetDynamicObject();
        myDynamicObject.SomeMethod();         // call a method   
        myDynamicObject.someString = "value"; // Set a field
        myDynamicObject[0] = 25;              // Access an indexer
    }
}

Но помилуйте – «это же то, о чем говорили большевики»! То есть не прошло и восьми лет, как в Microsoft согласились, что идея все же здравая. Былых разговоров о том, что динамика портит строго типизированный язык, и след простыл. Оно и логично. Зачем тогда вообще было делать тип object, да и повышающие приведения типов?

В блоге говорится, что реализовано это дело будет как раз на основе того самого DLR, но кто мешал тоже самое реализовать на базе рефлексии? Ведь DLR ничего особо нового не привнесет. Он только повысит производительность вызовов и (возможно) упростит реализацию этой возможности в компиляторе C#. В VB.NET такая возможность была с самого начала (хотя синтаксически было тяжело отличить нормальный вызов от динамического).

Теперь вопрос, сколько лет еще пройдет, прежде чем мы получим в эту возможность в составе готового продукта – .NET Framework? Год? Два? Три?

Теперь перенесемся на два года назад. В конференции по Nemerle, к разработке которого я тогда примкнул, появилась следующая тема:

http://nemerle.org/mailman/pipermail/devel-en/2006-July/002110.html

[nem-en] Late Binding in Nemerle
Snaury snaury at gmail.com
Sat Jul 1 16:33:42 CEST 2006

Hi everyone,

I was trying to grok nemerle's macros for some time when an idea
suddenly popped in my mind how I could do late binding aka dynamic
typing aka duck typing in a pretty simple and (maybe?) rich way. So I
wrote a macro for this, source code here:
http://www.furry.ru/kitsu/nemerle/Kitsu.LateBindingMacro.n.txt

It allows to use late binding on (I think) any expression, you just
have to wrap it with late, and use like this:

  late(expr).CallMe(param1, param2, param3).CallOtherMe(param, param,
param).Property[param, param, param] = value
...

Тем, кто не хочет заниматься переводом, вкратце объясню, о чем идет речь. Здесь говорится, что человеку пришла идея реализовать динамическое расширение в виде макроса с именем «late».

Все письмо я приводить не буду, тот, кому это интересно, может перейти по ссылке и прочесть все обсуждение. Так вот, обсуждение заняло примерно месяц, а уже 21 июля в SVN-репозиторий была «залита» первая версия макросов. Еще было пять правок, последняя из которых датируется 14 августа 2006 года. То есть вся работа над макросом, делающим то, что только проходит PR-стадию в Microsoft, была завершена менее чем за два месяца. Сам файл и всю его историю вы можете наблюдать по адресу:

http://nemerle.org/svn/nemerle/trunk/macros/Late.n

Недавно я был вынужден воспользоваться этим макросом при работе над генератором отчета (мне нужно было работать с automation Microsoft Word и Microsoft Excel, а динамически это делается проще всего) и я обнаружил, что макрос late не только работает стабильно, но и очень удобен в использовании. Вот, кстати, как это выглядит:

      /// Открывает файл в Excel и печатает его содержимое.
      public Print(reportPath : string) : void
{
  def workbook = late _app.Workbooks.Open(reportPath);
  
  foreach ((worksheetName, copies) in _worksheets)
    _ = late workbook.Worksheets[worksheetName].PrintOut(Copies=copies);

  _ = late workbook.Close(false); // Закрываем workbook
}

Видите строчки с late в начале? Вот это и есть динамический вызов. Понятно, что никакого DLR в распоряжении автора этого макроса не было, так что реализован вызов был через рефлексию. Может быть не очень шустро, но очень удобно. Чем? Например, в методе PrintOut имеется более десятка параметров, которые в случае использования обертки потребовалось бы задавать вручную (что, кстати, мне с первого раза вообще не удалось сделать). С late же я просто задал значение нужного мне параметра по имени, а все остальные late сам проинициализировал необходимым значениями, говорящими COM, что нужно использовать значения, принятые по умолчанию. Кроме того использование late позволило не добавлять ссылку на сборку, в которой описываются функции Excel, что позволило избежать привязки к конкретной версии Excel. В общем, просто и удобно. Так, как и должно было быть, я бы сказал!

А что же Microsoft? 25 января 2008 года в Microsoft заговорили о реализации подобной возможности в следующей версии C#. Видимо через несколько лет мы сможем ею воспользоваться.

Практически то же самое было с ковариантностью для интерфейсов и делегатов, с возможностью использовать в ограничениях (constrains) перечислений (enums) и многим другим. Но самое неприятное – это то, что многие очень полезные возможности так и не вышли за стадию «это народу не нужно».

Конечно, неплохо, что массовый пользователь языков программирования – mainstream-программист – через несколько лет сможет воспользоваться этими приятными мелочами, но непонятно, почему для реализации таких мелочей требуется вместо одного-двух месяцев 5-6 лет. И жутко обидно, что огромное количество очень удобных возможностей так и не попадут в mainstream-языки. Причем нам только остается гадать, произошло ли это вследствие того, что кто-то в Microsoft все еще находится на стадии «это народу не нужно», или группе разработки конкретного языках программирования в Microsoft просто не хватает времени на качественную реализацию и тестирование некоторой возможности.

Мне кажется, что макросы, аналогичные макросам Nemerle, были бы отличным выходом из положения. В Microsoft считают, что это слишком мощное оружие (“it’s a very big gun”), и попади они в руки «простым программистам» (читай, криворукому большинству), тотчас же появится куча несовместимых между собой макросов, которые породят хаос и ужас (такой стандартный, голливудский, апокалипсис, в общем). Меж тем как раз макросы могли бы решить проблему несовместимости, так как они-то, в отличие от возможностей, появляющихся в компиляторах Microsoft, описываются в конкретных пространствах имен, и имеют четкие и грамотные способы выявления (и разрешения) неоднозначностей.

Ну ладно, боязно помещать такую расширяемость в сам язык – это еще можно понять. Но ведь можно сделать некий SDK, которым смогут воспользоваться только подготовленные люди (не лезут же все, кому ни лень, драйверы для Windows писать из-за наличия и доступности Windows SDK?). Лучшие наработки было бы легко интегрировать в язык. При этом простые смертные смогли бы все же пользоваться тем, что в Microsoft не признали лучшим, на свой страх и риск.

Да даже если бы такой макро-SDK просто имелся в распоряжении самих разработчиков компилятора C#, то развитие языка шло бы куда быстрее и эффективнее. Не пришлось бы создавать разные C-omega или модифицировать SSCLI «Rotor», чтобы проверить какие-то там идеи. Их можно было бы быстро и просто проверить с помощью этого макро-SDK.

В общем, жаль! Выскажу свое, возможно надуманное мнение. Мне кажется, что за очередным «народу это не нужно», высказанным в форме “it’s a very big gun”, кроется все та же линейка: отрицание, замалчивание, пиар, реализация, популяризация. По крайней мере хотелось бы в это верить. Первые шаги, похоже, уже делаются. По всей видимости, одна из следующих версий компилятора C# будет написана на управляемом языке (надеюсь, что на C#). Это позволит сделать первый шаг в настраиваемости компилятора (точнее, процесса компиляции) – добавление событий позволяющих вмешиваться в процесс компиляции. Это должно вызвать эволюцию, которая, по моему высосанному из пальца мнению, должна привести в итоге к созданию того, что сейчас называется макросами Nemerle или LISP. Конечно, «это» будет иметь другое название, замечательный PR, и вызвать у непосвященных приступы восторга. Но это будет то, что нужно! По крайнем мере, я хотя бы помечтал об этом. :)


Эта статья опубликована в журнале RSDN Magazine #2-2008. Информацию о журнале можно найти здесь
    Сообщений 331    Оценка 416 [+1/-1]         Оценить