[Фича] Позволяет макросам работать с данными замыканий
От: VladD2 Российская Империя www.nemerle.org
Дата: 03.06.10 22:46
Оценка: 24 (1)
Описываемая фича доступна только из макросов.

Небольшое предисловие

Макросы немерла работают на стадии первичной типизации выражений. Компилятор читает не типизированное AST (PExpr), разберает его, вычисляет типы выражений и на основании полученной информации генерирует типизированное AST (TExpr).

В этот момент информации о замыканиях еще нет. В типизированном коде локальные переменные (которые в последствии превратятся в замыкания) представлены как простые ссылки на локальные переменные (так как будто замыканий нет и не будет).

Преобразование ссылок на локальные переменные производятся компилятором на самых подзних стадиях компиляции (непосредственно перед Emit-ом MSIL-а).

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

Реализация

Я добавил в типизированное AST (то есть в TExpr) следующие вхождения:
| ClosureObjectOf       { varRef : TExpr; }
| ClosureFieldOf        { varRef : TExpr; }


Если создать объект типа TExpr.ClosureObjectOf (или типа TExpr.ClosureFieldOf) и поместить в его поле varRef ссылку на локальную переменную (т.е. объект типа TExpr.LocalRef), то компилятор (на поздних стадиях) заменит TExpr.LocalRef на TExpr.FieldMember ссылающийся на поле замыкания которое подменяет локальную переменную.

Далее в генераторе MSIL-а я добавил две строчки:
| ClosureObjectOf(TExpr.FieldMember(obj, _))    => emit(obj);
| ClosureFieldOf(TExpr.FieldMember(obj, field)) => emit(TExpr.FieldOf(obj.Type, field));

Первая строка генерирует MSIL-код ссылки на объект замыкания.
Вторая генерирует MSIL-код загрузки информации о типе поля.

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

Зачем

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

Ранее код сгенерированный этим макросом вел себя немного не так как его аналог сгенерированный компилятором C#. В частности, если написать запрос вида:
mutable val = 1;
def query = dataSource.Where(x => x.SomeField == val);
def res1 = query.NToList();
val = 2;
def res2 = query.NToList();
Assert.AreNotEqual(res1, res2);

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

Теперь этот код должен отрабатывать корректно (как в C#).

ЗЫ

Фича доступна в ревизии 8903.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: [Фича] Позволяет макросам работать с данными замыканий
От: Ziaw Россия  
Дата: 04.06.10 04:24
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Описываемая фича доступна только из макросов.


VD>Ранее код сгенерированный этим макросом вел себя немного не так как его аналог сгенерированный компилятором C#. В частности, если написать запрос вида:

VD>
VD>mutable val = 1;
VD>def query = dataSource.Where(x => x.SomeField == val);
VD>def res1 = query.NToList();
VD>val = 2;
VD>def res2 = query.NToList();
VD>Assert.AreNotEqual(res1, res2);
VD>

VD>то код "не срабатывал", так как изменение значения переменной val не было "видно" для запроса.

VD>Теперь этот код должен отрабатывать корректно (как в C#).


Я правильно понял, что вместо переменной подставляется поле класса в котором находится код? Не создаст ли это проблем с рекурсивными методами?
Re[2]: [Фича] Позволяет макросам работать с данными замыкани
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.06.10 08:07
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Я правильно понял, что вместо переменной подставляется поле класса в котором находится код?


В результате подставляется ссылка на поле замыкания. Код аналогичен тому, что генерирует компилятор C#.

Z>Не создаст ли это проблем с рекурсивными методами?


Создай пример, попробуй. Я вообще не очень понимаю какая может быть рекурсия в линк-запросах, но даже если она будет, проблем это создать не должно.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: [Фича] Позволяет макросам работать с данными замыкани
От: Аноним  
Дата: 04.06.10 08:26
Оценка:
Здравствуйте, Ziaw, Вы писали:

Z>Я правильно понял, что вместо переменной подставляется поле класса в котором находится код? Не создаст ли это проблем с рекурсивными методами?


Да не должно бы, ведь на каждый вызов локальной функции создается свой объект замыкания.
Re: [Фича] Позволяет макросам работать с данными замыканий
От: catbert  
Дата: 04.06.10 08:37
Оценка: +1
Здравствуйте, VladD2, Вы писали:

VD>Фича доступна в ревизии 8903.


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

Опкод "closure_this" в ILEmitter-е, насколько я понимаю, остался случайно?
Re[2]: [Фича] Позволяет макросам работать с данными замыкани
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.06.10 08:52
Оценка:
Здравствуйте, catbert, Вы писали:

C>Опкод "closure_this" в ILEmitter-е, насколько я понимаю, остался случайно?


Да. Не вычистил результаты экспериментов. Ща попровим.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: [Фича] Позволяет макросам работать с данными замыкани
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.06.10 10:04
Оценка:
Здравствуйте, Аноним, Вы писали:

А>ведь на каждый вызов локальной функции создается свой объект замыкания.


Не совсем так.

Во-первых, есть оптимизация которая инлайнит функции на которые есть только одна ссылка и которые не используются в качестве значений (на которые нет ссылок).

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

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

Но в целом — да, проблем быть не должно, так как все эти оптимизации рассчитаны на подобное использование.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: [Фича] Позволяет макросам работать с данными замыкани
От: VladD2 Российская Империя www.nemerle.org
Дата: 04.06.10 11:02
Оценка: 6 (1)
Здравствуйте, catbert, Вы писали:

C>Что поражает, так это возможность ее реализовать буквально десятком строчек кода.


Строк конечно не много, но я потратил на эту фичу около 12 часов (две ночи ~6 часов).

Так как по ходу дела (разбираясь с кодом) я подправлял форматирование, то можно по исправленном форматированию можно оценить сколько кода пришлось проанализировать (в том числе и под отладчиком). Так что все на совсем просто. Тут как у хирургов. Для двух движений скальпелем нужно сделать 20 анализов, 2 рентгена и 5 консультаций .

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