Блоки итераторов, часть Седьмая: Почему нет анонимных итераторов?

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

Почему мы не разрешаем анонимные итераторы? Я был бы счастлив иметь анонимные блоки итераторов. Я хочу писать что-то вроде:

IEnumerable<int> twoints = ()=>{ yield return x; yield return x*10; };
foreach(int i in twoints) ...

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

Затраты велики. Переписывание итераторов – это самое сложное преобразование в компиляторе, а переписывание анонимных методов – второе по сложности. Анонимные методы могут быть вложены в другие анонимные методы, и анонимные методы могут быть внутри блоков итераторов. Так что, первое что мы делаем, это переписываем все анонимные методы так, чтобы они стали методами класса-замыкания. Это предпоследнее, что делает компилятор перед генерацией IL для метода. Как только этот шаг выполнен, переписчик итераторов может предполагать, что в блоке итератора нет анонимных методов; все они уже были переписаны. Так что переписчик итераторов может сконцентрироваться на переписывании итератора, не беспокоясь о том, что там могли остаться нереализованные анонимные методы.

Кроме того, блоки итераторов никогда не вкладываются друг в друга, в отличие от анонимных методов. Переписчик итераторов может предполагать, что все блоки итераторов находятся «на верхнем уровне».

Если позволить анонимным методам включать блоки итераторов, то оба этих предположения можно выкинуть в окно. У вас может быть блок итератора, который содержит анонимный метод, который содержит анонимный метод, который содержит блок итератора, который содержит анонимный метод, и… буээ. Теперь нам нужно написать проход переписывания, который может обрабатывать вложенные блоки итераторов и вложенные анонимные методы одновременно, объединив наши два самых запутанных алгоритма в один намного более запутанный алгоритм. Это было бы реально трудно спроектировать, реализовать, и протестировать. Я уверен, мы достаточно умны для этого. У нас тут сообразительная команда. Но мы не хотим брать на себя этот тяжкий труд ради «полезной, но не необходимой» возможности.

оригинал статьи