Макросы немерла работают на стадии первичной типизации выражений. Компилятор читает не типизированное AST (PExpr), разберает его, вычисляет типы выражений и на основании полученной информации генерирует типизированное AST (TExpr).
В этот момент информации о замыканиях еще нет. В типизированном коде локальные переменные (которые в последствии превратятся в замыкания) представлены как простые ссылки на локальные переменные (так как будто замыканий нет и не будет).
Преобразование ссылок на локальные переменные производятся компилятором на самых подзних стадиях компиляции (непосредственно перед Emit-ом MSIL-а).
Это делает невозможным не только манипулировать замыканиями и их полями, но даже получить хотя бы узнать какие же имена будут у переменной в которой хранится ссылка на замыкание и поля этого объекта которые создаются взамен локальных переменных.
Реализация
Я добавил в типизированное AST (то есть в TExpr) следующие вхождения:
Если создать объект типа TExpr.ClosureObjectOf (или типа TExpr.ClosureFieldOf) и поместить в его поле varRef ссылку на локальную переменную (т.е. объект типа TExpr.LocalRef), то компилятор (на поздних стадиях) заменит TExpr.LocalRef на TExpr.FieldMember ссылающийся на поле замыкания которое подменяет локальную переменную.
Первая строка генерирует MSIL-код ссылки на объект замыкания.
Вторая генерирует MSIL-код загрузки информации о типе поля.
Таким образом не имея фактически возможности манипулировать замыканиями в коде макросов, становится возможным сгенерировать ссылку на замыкание и/или на его поле, а так же генерировать код возвращающий информацию о типах полей замыканий.
Зачем
Данная фича добавлена для того, чтобы устранить проблему в макросе реализующем поддержку Linq.
Ранее код сгенерированный этим макросом вел себя немного не так как его аналог сгенерированный компилятором C#. В частности, если написать запрос вида:
Здравствуйте, VladD2, Вы писали:
VD>Описываемая фича доступна только из макросов.
VD>Ранее код сгенерированный этим макросом вел себя немного не так как его аналог сгенерированный компилятором C#. В частности, если написать запрос вида: VD>
VD>то код "не срабатывал", так как изменение значения переменной val не было "видно" для запроса.
VD>Теперь этот код должен отрабатывать корректно (как в C#).
Я правильно понял, что вместо переменной подставляется поле класса в котором находится код? Не создаст ли это проблем с рекурсивными методами?
Re[2]: [Фича] Позволяет макросам работать с данными замыкани
Здравствуйте, Ziaw, Вы писали:
Z>Я правильно понял, что вместо переменной подставляется поле класса в котором находится код?
В результате подставляется ссылка на поле замыкания. Код аналогичен тому, что генерирует компилятор C#.
Z>Не создаст ли это проблем с рекурсивными методами?
Создай пример, попробуй. Я вообще не очень понимаю какая может быть рекурсия в линк-запросах, но даже если она будет, проблем это создать не должно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: [Фича] Позволяет макросам работать с данными замыкани
От:
Аноним
Дата:
04.06.10 08:26
Оценка:
Здравствуйте, Ziaw, Вы писали:
Z>Я правильно понял, что вместо переменной подставляется поле класса в котором находится код? Не создаст ли это проблем с рекурсивными методами?
Да не должно бы, ведь на каждый вызов локальной функции создается свой объект замыкания.
Re: [Фича] Позволяет макросам работать с данными замыканий
Здравствуйте, Аноним, Вы писали:
А>ведь на каждый вызов локальной функции создается свой объект замыкания.
Не совсем так.
Во-первых, есть оптимизация которая инлайнит функции на которые есть только одна ссылка и которые не используются в качестве значений (на которые нет ссылок).
Во-вторых, замыкания создаются скорее не для функций которые захватывают контекст, а для функций чьи переменные захватываются.
В-третьих, замыкания создаются только если переменные реально используются во вложенных унциях и эти функции не инлайнятся.
Но в целом — да, проблем быть не должно, так как все эти оптимизации рассчитаны на подобное использование.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: [Фича] Позволяет макросам работать с данными замыкани
Здравствуйте, catbert, Вы писали:
C>Что поражает, так это возможность ее реализовать буквально десятком строчек кода.
Строк конечно не много, но я потратил на эту фичу около 12 часов (две ночи ~6 часов).
Так как по ходу дела (разбираясь с кодом) я подправлял форматирование, то можно по исправленном форматированию можно оценить сколько кода пришлось проанализировать (в том числе и под отладчиком). Так что все на совсем просто. Тут как у хирургов. Для двух движений скальпелем нужно сделать 20 анализов, 2 рентгена и 5 консультаций .
Если бы код компилятора был бы в более качественном состоянии, подобные вещи можно было бы реализовать вообще на раз. И вообще, поддержка и развитие компилятора шли бы проще. А то я вот уже четвертый год вожусь с компилятором и все равно еще не все его части понимаю. А что говорить о тех кто только залез в него? У них вообще крыша должна съезжать.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.