Alex Polozov (skiminog) wrote,
Alex Polozov
skiminog

Category:

Weaver — первые впечатления

Это еще не мануал по языковым изменениям и пр., как прошлогодний с Тибуроном. Это просто мои первые впечатления после того, как я немножко поигрался с новой версией RAD Studio.

Предисловие, или отвлечённые размышления про Embarcadero и Microsoft

У ребят из CodeGear Embarcadero, как я понял, есть одна занятная привычка: они не заморачиваются. Годовой релиз, по их мнению — это ровно два КРУПНЫХ нововведения в языке и компиляторе, пяток мелких, повысить версии поддерживаемых БД/протоколов (возможно, добавить пару новых — если настроение с утра будет подходящим), подогнать VCL под свежие возможности Винды и прикола ради выполнить десяток-другой запросов из QC по поводу IDE. А вместе, в общем и целом, набирается достаточная база для того, чтобы на протяжении одного-двух месяцев наполнять блоги delphifeeds.com демонстративными постами и разъезжать по миру с конференциями и демонстрациями. Ах да, еще есть CodeRage, на котором обязательно надо рассказать разработчикам, как теперь они могут быстро и просто по-новому делать то, что они делали вот уже много лет как собственными усилиями.

На самом деле я сейчас произнёс не более чем длинную скептическую тираду =) Потому что всё это перечисление не имеет никакого смысла, пока я не уточню, что же ИМЕННО выбрали в качестве "крупных нововведений" в этом году коджировцы. И вот тогда уже можно о чём-то говорить. Самое интересное вот в чём: релиз RAD Studio выходит раз в год, релиз Visual Studio вместе с новым .NET Framework — раз года в три. Каждый релиз последней, соответственно, приносит нам примерно в 3 раза больше фич, чем типичный релиз первой. Иногда и того меньше (фичи C# 4, к примеру, по сравнению с C# 3 тянут как раз на годик работы коджировцев). Но вот в чём загвоздка: эти фичи доработаны. То есть ты смотришь на них, читаешь один-два поста в блогах MSDN и сразу думаешь: "Ага, отлично, вот это я могу приткнуть сюда, а вон то так и просится вон в тот мой класс месячной давности". И все рады и довольны. Коджировцы же, в свою очередь, работают несколько иначе. После того, как Хейлсберг, гениальный представитель стыка тысячелетий, ушёл в MS, последние версии Delphi исповедуют принцип "А теперь возьмём вон ту фичу C#, сделанного нашим же идеологом с учётом прошлых граблей, и реализуем её в нативном Делфи, как он и хотел бы". Но поскольку они не Хейлсберг, то фича реализовывается... ммм... не до конца. Их можно понять, у них меньше людей, времени ровно год, а не три, бюджет поджимает... но всё-таки каждый август я, читая delphifeeds, восклицаю "Wow!", а через некоторое время, немножко покодив на свежем релизе, чешу затылок и думаю "Твою мать..."

Хотите конкретики? OK, поясняю, что я имею в виду. Возьмём в качестве примера 2009 год и дженерики. Ясное дело, дженерики — это был гигантский прорыв в Делфи, их многие годы ждали, без них было дико неудобно программировать кучу специфических вещей, с этим никто и не спорит. Но вот что интересно... дженерики-то ввели, а обеспечить их должную поддержку на требуемом уровне так и не получилось (не успели?). К примеру, в IDE простейший рефакторинг "Rename" при попытке подсунуть ему обобщённый тип начинал заикаться и материть разработчика непечатными словами. IDE считала ошибками безобиднейшие конструкции DeCAL2009, из-за чего я практически не мог пользоваться рефакторингом во время кодинга на Делфи: ну не жует она код, в котором есть "красные подчеркивания"! Хотя все конструкции корректны, и компилятор спокойно обрабатывал весь код без единого варнинга даже. Дальше, если у нас уже есть модуль Generics.Collections с обобщёнными классами и интерфейсами, то почему бы не переделать на него VCL? Почему-то до сих пор банальнейший TListView своё свойство Items представляет как специфический класс TListItems, а не просто а-ля TList<TListIem>, хотя функционал у них идентичен. Обратная совместимость — это замечательно, но в итоге библиотека хромает на обе ноги. В конце концов, чтобы решить проблемы обратной совместимости, можно вспомнить, как в незапамятные времена добрые люди придумали интерфейсы.

К чему я веду, собственно... Любая новая возможность в C# появляется интегрированной: типичные сценарии её использования продуманы и встроены в FCL, IDE ведёт себя так, словно фича была здесь всегда, и дополнительно предлагается кучка новых классов/структур/интерфейсов/методов старых классов, которые удобно используют эти новые возможности. Delphi же исторически предназначен для сторонних разработчиков, традиция писать под него сотни новых компонентов и библиотек не переведётся, пока существует на свете сам Delphi. Поэтому любая новая возможность Делфи вводится в компилятор, обеспечивается простейшей базовой поддержкой, документируется с парой примеров — и гуляйте, ребята, пишите монструозные библиотеки с её юзаньем, улучшайте программистам жизнь, мы своё дело сделали.

И это удручает.

Языковые возможности

Декларативное программирование, в отличие от императивного, не так плотно вошло в нашу жизнь. На самом деле миллионы человек ежедневно пользуются его плодами, бродя по HTML-страничкам (да-да, несмотря на то, что HTML — язык разметки документа, его также смело можно назвать и попросту декларативным ЯП). Но вот активное использование этой концепции в других областях, кроме Веб-разметки, скриптинга и пр., а также с более продвинутыми возможностями, встречалось очень редко. До тех пор, пока команда разработчиков .NET не предложила всем атрибуты.

Простая ведь штука, на самом-то деле. Просто определённый вид пометки любой сущности с возможностью конкретизации этой пометки несколькими параметрами. Самое интересное в том, что сам атрибут по факту ничего не делает: для того, чтобы воспользоваться его возможностями, нужно написать где-нибудь код, который в run-time берет информацию о требуемом объекте, проверяет наличие у него некоторого атрибута, и в случае его присутствия уже делает своё чёрное дело, чего, собственно, и хотел человек, навесивший на объект этот атрибут. Часто это не слишком-то удобно на самом деле, но уж как есть. С помощью атрибутов отлично реализуется парадигма АОП (аспектно-ориентированного программирования), что, собственно, и сделали ребята из RemObjects, родив для Delphi Prism замечательный фреймворк под названием Cirrus. А когда у тебя есть АОП-фреймворк — у тебя есть краткий и не морозящий мозги способ реализовать логирование, многопоточность, запись сущностей в БД, контрактное программирование и кучу прочих прелестей, которые иначе вылились бы в гору лишних мусолящих взгляд строчек в твоем исходнике. Шикарно, на самом-то деле. Главное, чтобы такой фреймворк кто-нибудь написал — или продемонстрировал общие принципы его создания.

Вот тут и кроется проблема, затронутая мною в предисловии. Да, в Делфи теперь есть шарповские атрибуты, они аналогичным образом наследуются от TCustomAttribute, имеют всё тот же интуитивный синтаксис и подчиняются тем же законам использования. Вот только в среде они обозначены лишь четырьмя страничками справки. Я не нашёл в VCL и RTL ни одного сделанного руками коджировцев атрибута. Ни тебе Serializable, ни Log, ни Obsolete. Возможно, атрибуты были использованы, чтобы дать нам свежие возможности RTTI, не знаю; в справочной системе об этом нет ни слова, в модуле Rtti мною не было найдено ни одного атрибута. В общем и целом, пока какая-то добрая душа не реализует полный фреймворк, аналогичный Cirrus`у, использовать атрибуты бесполезно. Потому что любой мой собственный исходник будет в итоге велосипедом.
Хочется большего и прямо сейчас — идём на delphifeeds, читаем один практический пример. Нет, лучше еще один.

Да, кстати. Атрибуты не полностью скопированы с C#. В справочной системе я, к примеру, не нашёл способа, как применить атрибут к возвращаемому значению функции. То, для чего в Шарпе предназначены атрибутные префиксы, а-ля [return: MinimumInteger(10)]. Про подобные префиксы устранения неоднозначности в Делфи (а их же тьма-тьмущая: assembly, return, type, method, param...) в справке не сказано ни слова.

Теперь про RTTI. Здесь у меня нет ни единой претензии. Подобной универсальной системы ждали все, и ждали довольного долго, и теперь работа с RTTI в Делфи ничем не уступает дотнетовскому или джавовскому отражению. Просто скопирую сюда код из статьи, совмещающий демонстрацию использования RTTI и атрибутов:
var
  LContext: TRttiContext;
  LType: TRttiType;
  LAttr: TCustomAttribute;
begin
  { Create a new Rtti context }
  LContext := TRttiContext.Create
 
  { Extract type information for TSomeType type }
  LType := LContext.GetType(TypeInfo(TSomeType));

  { Search for the custom attribute and do some custom processing }
  for LAttr in LType.GetAttributes() do
    if LAttr is TSpecialAttribute then
      WriteLn(TSpecialAttribute(LAttr).FValue);
 
  { Destroy the context }
  LContext.Free;
end;

Вот модулем Rtti я теперь с удовольствием буду пользоваться на каждом шагу. И всем рекомендую.
Чтобы кастомизировать процесс создания метаинформации для RTTI, можно использовать новые директивы {$RTTI} и {$WEAKLINKRTTI}. Они дают всю необходимую гибкость.

Дальше идёт директива delayed. Степень полезности — средняя, но применение найти можно. Короче говоря, это отложенный вызов функции из библиотеки. Если вы собираетесь экспортировать функцию из дллки, в которой по какой-то причине этой функции может и не быть (проблемы версий), пишете delayed, а в рантайме уже проверяете, какую реализацию использовать: библиотечную, точно зная, что при данных условиях вызов функции не навернется, или собственную. Таким образом был реализован механизм естественного ввода (жестов и тачей) в VCL Weaver`а: на Windows 7 используем системные функции, а на предыдущих ОС — собственный движок. Исходник из delphifeeds:
function CloseDesktop; external user32 name 'CloseDesktop';  
function CloseTouchInputHandle; external user32 name 'CloseTouchInputHandle' delayed;  
function CloseWindow; external user32 name 'CloseWindow';  

...

if OSVersion = WINDOWS_7 then  
  CloseTouchInputHandle  
else  
  MyInternalSimplerClose;

Главная польза, наверное — отсутствие пяти строк дополнительного кода везде, где раньше с этой целью использовали динамическую загрузку DLL.

Последняя фича действительно очень и очень востребована — это кастинг интерфейсов обратно в объект, на который он ссылается. Если вы создали экземпляр некоторого объекта, реализующего некоторый интерфейс, а потом присвоили ссылку на этот объект переменной интерфейсного типа, вы можете воспользоваться старыми добрыми операторами as и is, чтобы привести эту переменную обратно к объектному типу. Да что там, даже старый паскалевский небезопасный кастинг (с использованием имени типа) здесь сработает. Все правила остаются в силе — если запрошенный класс не реализует данный интерфейс, as выбросит исключение, is вернёт false, а небезопасный кастинг просто присвоит итоговой переменной nil. Всё просто.
Работает такой кастинг только для дельфийских объектов. COM`у — нет =) Почему — читайте здесь

Продолжение следует...

Следующую часть рассказа, описывающую новенькие красоты VCL, RTL и IDE, я сегодня уже не смогу рассказать вам, любезные читатели. Оставайтесь на нашей волне денек-другой, и все будет, обещаю. Потому что впечатление от этих возможностей у меня сейчас на порядок выше, чем от тех же атрибутов.
Tags: delphi, weaver
Subscribe

  • (no subject)

    Лучшее занятие холодным зимним воскресеньем — это немного покормить одного не сильно толстого, но все же тролля :)

  • ToDo: сентябрь

    - PluginUpdater: несколько видов клиентов, несколько видов серверов, человеческие запросы, очередность способов проверки, бекап, управление…

  • Weaver

    Итак, вчера Embarcadero RAD Studio 2010 (Weaver) всё-таки релизнулся. Свои впечатления, наверное, выскажу подробно и обстоятельно (как всегда) после…

  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 19 comments

  • (no subject)

    Лучшее занятие холодным зимним воскресеньем — это немного покормить одного не сильно толстого, но все же тролля :)

  • ToDo: сентябрь

    - PluginUpdater: несколько видов клиентов, несколько видов серверов, человеческие запросы, очередность способов проверки, бекап, управление…

  • Weaver

    Итак, вчера Embarcadero RAD Studio 2010 (Weaver) всё-таки релизнулся. Свои впечатления, наверное, выскажу подробно и обстоятельно (как всегда) после…