Re[11]: «Собаку съел»
От: samius Япония http://sams-tricks.blogspot.com
Дата: 23.01.17 15:27
Оценка: +1
Здравствуйте, Serginio1, Вы писали:

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


S>>> И чем тебе не нравится?

S>>> Инлайнинг в рантайме!
S>>Да все нравится, но где же обещаный инлайниг параметрически полиморфного компаратора?


S> А это что?


S>
S>public static IEnumerable<T> Compose<T, Y>(this IEnumerable<T> src, Expression<Func<T, Y>> propertyExpression, Expression<Func<Y, bool>> func)
S>        {
S>            return src.Where(Expression.Lambda<Func<T, bool>>(Expression.Invoke(func, propertyExpression.Body), propertyExpression.Parameters).Compile());
S>        }
S>


Без понятия. Точнее — это код. Но какое отношение он имеет к инлайнингу параметрически полиморфного компаратора — я все еще пытаюсь выяснить. Даже с учетом того что Func<Y, bool> можно заменить на Func<Y, Y, bool>, все равно не натягивается.

Давай так, я напишу, что меня смущает во всей этой магии, и закончим на этом.
1) Параметрически полиморфный компаратор — это нонсенс. Просто потому что он не нужен. Ключевое слово здесь "параметрический", что означает "для любого типа T". Нет смысла сравнивать величины конкретного типа методом, работающим для любого типа. Значения сравниваются каждый раз специальным образом. Т.е. способ сравнения должен быть указан специально для любого типа T (не считая подтипы). Такой тип полиморфизма называется специальным, или ad-hoc. Перегрузка функций по типу аргумента — это как раз об ad-hoc полиморфизме. Это проявление статического полиморфизма, или полиморфизма времени компиляции (тип должен быть известен во время компиляции).
2) Компаратор можно записать как бы параметрически для любого T
Comparer<T>.Default.Compare(t1, t2);

Проблема в том, что для любого T работать он не будет, а будет работать для тех типов, чьи способы сравнения можно определить в рантайме. Итого, хоть оно похоже на параметрический полиморфизм, реально это специальный полиморфизм времени выполнения, динамический.
Насколько я понимаю, речь совсем не об этом случае. Ведь что бы заинлайнить обращение IComparer<T>.Compare и перейти от динамического разрешения к статическому — это линк реврайтер должен еще суметь доказать, что ему передан экземпляр компарера, который ведет себя в точности как встроенный оператор сравнения.
3) далее переходим к методу
.Where<T>(x => x > q)

Здесь тип T C#-у известен на стадии компиляции. Он задается неявно по типу первого неявного аргумента IEnumerable<T> (в общем случае неком C<T>, если заглянуть в спецификацию). Поэтому дальнейшая компиляция выражения "x > q" при известном компилятору типу T не вызывает вопросов. Компилятор еще в момент компиляции знает о том, что у типа Int32 есть оператор сравнения. Попробуй так сделать с любым типом, не имеющим оператор сравнения, компилятор выдаст ошибку.
4) Итого, в момент компиляции компилятор знает, что за компаратор используется для известного ему типа, и генерирует код, обращающийся к этому компаратору. Именно этот код я достал из рефлектора (ILSpy), про который ты сказал что это результат MakeGenericMethod(или MakeGenericType, не помню точно). Так вот, именно в этом методе, обращение к компаратору уже некуда инлайнить (по крайней мере на уровне языка). После джиттинга уже именно обращение к оператору сравнения для Int32 приведет к реальному вызову инструкции сравнения на самом низком уровне.
5) LINQ реврайтер инлайнит Where, Select и прочую фигню (я уже писал об этом), но при этом код вызова оператора сравнения для Int32 переносит как есть в тело сгенерированного им метода. С оператором сравнения целых ровно ничего при этом не происходит. Он как был записан на уровне языка, так и остался им же записан. И после джиттинга вставит ровно такую же инструкцию, как и в пункте выше.

Итого, инлайнинга параметрически полиморфных компараторов нет, инлайнинга полиморфных компараторов нет, инлайнинга комрпаратора вообще нет. Есть инлайнинг параметрически полиморфных Where, Select, но не компаратора. Есть инлайнинг Sum, но он не параметрически полиморфен (ad hoc).
Разобрались?

S>>> Это тебе не кодогенерация при специализации шаблона.

S>>Так что за кодогенерация при специализации шаблона? Однажды я уже выразил недоумение по поводу этого сочетания терминов.

S> Кстати просвети меня, как происходит специализация шаблона, который построен на перегрузке методов, за малым исключением где применяются ссылки на методы.

Извини, я неверно воспринял смысл слова "кодогенерация". С кодогенерацией при специалиации шаблона все в порядке. Я подумал о чем-то вроде T4.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.