зачем делать два Enumerator'а ?
От: Jack128  
Дата: 12.12.15 11:22
Оценка:
В реализации ImmutableQueue (хотя наверняка не только в нем)

есть 2 энумератора:
как структура (для foreach паттерна):
https://github.com/dotnet/corefx/blob/a465212d79ac68656b0a8a6d5e1c6e984b5680d5/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue%601.cs#L269

и как класс (реализует IEnumerator<>): https://github.com/dotnet/corefx/blob/a465212d79ac68656b0a8a6d5e1c6e984b5680d5/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue%601.cs#L358

собственно вопрос: почему бы не оставить одну реализацию (struct) и в ней реализовать IEnumerator<> ?

Кста, а где реализация List<> , что то не могу найти ?
Re: зачем делать два Enumerator'а ?
От: vorona  
Дата: 12.12.15 19:42
Оценка:
Здравствуйте, Jack128, Вы писали:
http://stackoverflow.com/a/33872004
Re[2]: зачем делать два Enumerator'а ?
От: Jack128  
Дата: 12.12.15 20:36
Оценка: +1
Здравствуйте, vorona, Вы писали:

V>Здравствуйте, Jack128, Вы писали:

V>http://stackoverflow.com/a/33872004

Хм, а какое отношение это имеет к вопросу? эти энемераторы же не рослин генерит, это вручную написанный код.
Re: зачем делать два Enumerator'а ?
От: xy012111  
Дата: 12.12.15 21:50
Оценка:
Здравствуйте, Jack128, Вы писали:

J>В реализации ImmutableQueue (хотя наверняка не только в нем)

J>есть 2 энумератора:
J>как структура (для foreach паттерна):
J>https://github.com/dotnet/corefx/blob/a465212d79ac68656b0a8a6d5e1c6e984b5680d5/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue%601.cs#L269
J>и как класс (реализует IEnumerator<>): https://github.com/dotnet/corefx/blob/a465212d79ac68656b0a8a6d5e1c6e984b5680d5/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableQueue%601.cs#L358
J>собственно вопрос: почему бы не оставить одну реализацию (struct) и в ней реализовать IEnumerator<> ?

Когда так (как вы предлагаете) пытаются сделать, выглядит это как будто бы автор хочет сэкономить на наборе текста.

Структуре, возвращаемой из публичного GetEnumerator() никакой интерфейс не нужен. А из реализации IEnumerable::GetEnumerator() нужно наоборот, вернуть [ссылочный тип] интерфейс. Хоть реализация одна и та же, внешние требования разные. Если для вас это важно, уже из-за SRP следует разделить.

Подозреваю, что авторы стремились избавиться от боксинга. Зачем за него платить, если можно легко и просто скопипастить один раз немного кода и завернуть его в другую приватную обёртку?

J>Кста, а где реализация List<> , что то не могу найти ?


Некоторые типы нужно искать в корецлр https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/Collections/Generic/List.cs
Re: зачем делать два Enumerator'а ?
От: Sinix  
Дата: 13.12.15 14:15
Оценка: +1
Здравствуйте, Jack128, Вы писали:

J>В реализации ImmutableQueue (хотя наверняка не только в нем)

Второй поддерживает IEnumerator (не генерик) + IDisposable + Reset(). Первый максимально дешёвый. MoveNext() даже инлайниться должен.

J>собственно вопрос: почему бы не оставить одну реализацию (struct) и в ней реализовать IEnumerator<> ?

На одно поле больше + не инлайнится из-за throw.
Re[2]: зачем делать два Enumerator'а ?
От: xy012111  
Дата: 13.12.15 18:46
Оценка: 38 (1)
Здравствуйте, Sinix, Вы писали:

J>>собственно вопрос: почему бы не оставить одну реализацию (struct) и в ней реализовать IEnumerator<> ?

S>На одно поле больше + не инлайнится из-за throw.

Так явно throw и во втором нет, там же просто вызов ThrowIfDisposed(); (как раз отчасти специально для инлайнинга так делают) поэтому и такой мувнекст может заинлайниться.

Другое дело — я не уверен, что косвенный вызов MoveNext() через интерфейс сможет заинлайниться.
Re[3]: зачем делать два Enumerator'а ?
От: Sinix  
Дата: 13.12.15 19:30
Оценка: 7 (3)
Здравствуйте, xy012111, Вы писали:


S>>не инлайнится из-за throw.


X>Так явно throw и во втором нет, там же просто вызов ThrowIfDisposed();


Мдя, тут протормозил Не, можно конечно посчитать размер il-кода (вдруг там из-за пары лишних инструкций получается > 34 байт и ограничение по размеру срабатывает), но после вот этой багофичи и после свежих планов по инлайнингу (рассматривают вариант с machine learning) я зарёкся спорить на тему что инлайнится, что нет. Только проверять и только каждый конкретный случай в индивидуальном порядке. Текущее поведение не задокументировано, но можно глянуть тесты.

Короче, теперь я тоже присоединяюсь к "а фиг его знает".


X>Другое дело — я не уверен, что косвенный вызов MoveNex() через интерфейс сможет заинлайниться.

И не должен, структура вполне может реализовать интерфейс явно, а сама соответствовать enumerator pattern.
2all: Если кто отстал от обсуждения, то обсуждаем примерно вот это.
Re[2]: зачем делать два Enumerator'а ?
От: Jack128  
Дата: 14.12.15 07:48
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, Jack128, Вы писали:


J>>В реализации ImmutableQueue (хотя наверняка не только в нем)

S>Второй поддерживает IEnumerator (не генерик) + IDisposable + Reset(). Первый максимально дешёвый. MoveNext() даже инлайниться должен.
Ну вот возьмем например List&lt;T&gt;.Enumerator, и IEnumerator, и IDisposable, и Reset, все есть. Но структура.

J>>собственно вопрос: почему бы не оставить одну реализацию (struct) и в ней реализовать IEnumerator<> ?

S>На одно поле больше + не инлайнится из-за throw.
Если сделать пустую реализацию IDisposable, то и поле не нужно. С инлайнингом тоже вроде разобрались.
Re: зачем делать два Enumerator'а ?
От: vorona  
Дата: 17.12.15 11:22
Оценка: 72 (4)
Здравствуйте, Jack128, Вы писали:

https://github.com/dotnet/corefx/blob/master/src/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray%601%2BEnumerator.cs#L14
Re[4]: зачем делать два Enumerator'а ?
От: Sharov Россия  
Дата: 17.12.15 18:11
Оценка:
Здравствуйте, Sinix, Вы писали:

S>по инлайнингу (рассматривают вариант с machine learning)


Простите, а это Вы о чем? Связь какая?
Кодом людям нужно помогать!
Re[5]: зачем делать два Enumerator'а ?
От: Sinix  
Дата: 17.12.15 18:50
Оценка: 4 (1)
Здравствуйте, Sharov, Вы писали:

S>Простите, а это Вы о чем? Связь какая?

Proposed Plans for Inlining:

Given the wide range of scenarios, targets, and the two distinct code bases, we propose to heavily rely on machine learning techniques for building and tuning the Profitability components of the inliners.

и далее по тексту.

Вообще, всю документашку в coreclr вполне можно пролистать. Никаких особых секретов там нет, сплошные нюансы. Зато процентов эдак 50 нигде до этого не озвучивалось.
Re[2]: зачем делать два Enumerator'а ?
От: xy012111  
Дата: 04.02.16 22:03
Оценка: 19 (1)
Здравствуйте, xy012111, Вы писали:

J>>В реализации ImmutableQueue (хотя наверняка не только в нем)

J>>есть 2 энумератора:

J>>собственно вопрос: почему бы не оставить одну реализацию (struct) и в ней реализовать IEnumerator<> ?

X>Подозреваю, что авторы стремились избавиться от боксинга. …


И не один я так думал (из System.Slices):
/// <summary>
/// enumerator that implements <see cref="IEnumerator{T}"/> pattern (including <see cref="IDisposable"/>).
/// it is used by LINQ and foreach when Slice is accessed via <see cref="IEnumerable{T}"/>
/// it is reference type to avoid boxing when calling interface methods on stuctures
/// </summary>
private class EnumeratorObject : IEnumerator<T>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.