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

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


S>>Но это еще не компаратор, это только его сигнатура. Осталось написать параметрически полиморфное тело компаратора и продемонстрировать как оно инлайнится.

S> То есть

S>
S>System.Linq.Expressions.Expression<Func<int,int, int>> expr = (i,x) => i -x;
S>

К сожалению, полиморфизма в этой записи я вообще не наблюдаю. Никакого. Где же он?

S> А как использовать деревья выражений я тебе уже кучу сслок давал.

Я в курсе, что это и как использовать. И работал с ними от момента их появления.
Re[8]: «Собаку съел»
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 23.01.17 09:37
Оценка:
Здравствуйте, samius, Вы писали:

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


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


S>>>Но это еще не компаратор, это только его сигнатура. Осталось написать параметрически полиморфное тело компаратора и продемонстрировать как оно инлайнится.

S>> То есть

S>>
S>>System.Linq.Expressions.Expression<Func<int,int, int>> expr = (i,x) => i- x;
S>>

S>К сожалению, полиморфизма в этой записи я вообще не наблюдаю. Никакого. Где же он?
Это уже специализация. А дженерик метод ты удалил. А там как раз и используется обобщенный вариант
Для С++ это перегрузка оператора

На С++ ты тоже должен сделать перегрузку операторов сравнения
int operator>(shop v,shop w)
{
    if (strcmp (v.madein,w.madein)>0) return 1;
    if (strcmp (v.madein,w.madein)<0) return 0;

    if (strcmp (v.proiz,w.proiz)>0) return 1;
    if (strcmp (v.proiz,w.proiz)<0) return 0;

    if (strcmp(v.x.item,w.x.item)>0) return 1;
    if (strcmp(v.x.item,w.x.item)<0) return 0;
    else return 0;
}


При этом этих вариантов сравнений может быть вагон и маленькая тележка для обычных SQL таблиц.


System.Linq.Expressions.Expression<Func<T,T,int>>



S>> А как использовать деревья выражений я тебе уже кучу ссылок давал.

S>Я в курсе, что это и как использовать. И работал с ними от момента их появления.
И чем тебе не нравится?
Инлайнинг в рантайме!
Это тебе не кодогенерация при специализации шаблона.
и солнце б утром не вставало, когда бы не было меня
Отредактировано 23.01.2017 10:09 Serginio1 . Предыдущая версия .
Re[9]: «Собаку съел»
От: samius Япония http://sams-tricks.blogspot.com
Дата: 23.01.17 13:11
Оценка:
Здравствуйте, Serginio1, Вы писали:

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


S>>К сожалению, полиморфизма в этой записи я вообще не наблюдаю. Никакого. Где же он?

S> Это уже специализация. А дженерик метод ты удалил. А там как раз и используется обобщенный вариант
Специализация параметрического полиморфизма — это новое слово в науке. И ничего я не удалял.

S>Для С++ это перегрузка оператора

Перегрузка оператора — это проявление ad hoc полиморфизма.

S>На С++ ты тоже должен сделать перегрузку операторов сравнения

За C++ я спокоен, пока никто не обещал в нем инлайнинг параметрически полиморфного компаратора.
S> При этом этих вариантов сравнений может быть вагон и маленькая тележка для обычных SQL таблиц.
Это очевидно.

S>
S>System.Linq.Expressions.Expression<Func<T,T,int>> 
S>

Оп, опять нет тела в обобщении.


S>>> А как использовать деревья выражений я тебе уже кучу ссылок давал.

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

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

Так что за кодогенерация при специализации шаблона? Однажды я уже выразил недоумение по поводу этого сочетания терминов.
Re[10]: «Собаку съел»
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 23.01.17 14:05
Оценка:
Здравствуйте, samius, Вы писали:


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)
        {
            return src.Where(Expression.Lambda<Func<T, bool>>(Expression.Invoke(func, propertyExpression.Body), propertyExpression.Parameters).Compile());
        }

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

Кстати просвети меня, как происходит специализация шаблона, который построен на перегрузке методов, за малым исключением где применяются ссылки на методы.
и солнце б утром не вставало, когда бы не было меня
Re[57]: «Собаку съел»
От: vdimas Россия  
Дата: 23.01.17 14:59
Оценка: +2
Здравствуйте, samius, Вы писали:

S>> Никто тебе не мешает создать свою реализацию на структуре.

S>>В большинстве случаев это пережитки эпохи без дженериков
S>Конечно не мешает. Но что-то мешает мне свою реализацию на структуре подать по значению в LINQ методы типа Where.

Восхищаюсь твоим терпением, реально. ))
Re[7]: «Собаку съел»
От: vdimas Россия  
Дата: 23.01.17 15:02
Оценка:
Здравствуйте, Serginio1, Вы писали:

S> На самом деле, что можно в рантайме, то можно и на этапе компиляции. Так или иначе компилятор строит AST дерево, и можно подставлять не адрес на функцию, а разворачитвать тело функции по адресу на этапе компиляции в CIL код.

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>

Отлично. ))
ЧТД.
Re[11]: «Собаку съел»
От: vdimas Россия  
Дата: 23.01.17 15:04
Оценка:
Здравствуйте, Serginio1, Вы писали:

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>

Это то, что должен был генерить компилятор.
Но приходится тебе.
Re[12]: «Собаку съел»
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 23.01.17 15:18
Оценка:
Здравствуйте, vdimas, Вы писали:

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


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>>

V>Это то, что должен был генерить компилятор.
V>Но приходится тебе.

А я уже в 1000 раз привожу ссылки где это делается
Optimising LINQ
roslyn-linq-rewrite


Все, что можно руками можно автоматизировать. Сейчас с развитием Рослина много оптимизаций на уровне Кода в CIL.
Кроме того есть Net Native и там намного проще делать оптимизации из-за ограничения в рефлексии.
Все идет своим чередом.
и солнце б утром не вставало, когда бы не было меня
Отредактировано 23.01.2017 15:22 Serginio1 . Предыдущая версия .
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.
Re[58]: «Собаку съел»
От: samius Япония http://sams-tricks.blogspot.com
Дата: 23.01.17 15:49
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Восхищаюсь твоим терпением, реально. ))


Пока удается держать дистанцию от перехода на личности, да при полном отсутствии других параллельных дискуссий (и конфликтов), все нормально.
Re[12]: «Собаку съел»
От: alex_public  
Дата: 23.01.17 18:09
Оценка:
Здравствуйте, samius, Вы писали:

S>1) Параметрически полиморфный компаратор — это нонсенс. Просто потому что он не нужен. Ключевое слово здесь "параметрический", что означает "для любого типа T". Нет смысла сравнивать величины конкретного типа методом, работающим для любого типа.


Ну вообще то смысл есть. Вот http://ru.cppreference.com/w/cpp/utility/functional/equal_to простейший пример.

P.S. То, что там всё инлайнится, наверное можно даже и не уточнять. )))
Отредактировано 23.01.2017 18:11 alex_public . Предыдущая версия .
Re[13]: «Собаку съел»
От: samius Япония http://sams-tricks.blogspot.com
Дата: 23.01.17 18:43
Оценка:
Здравствуйте, alex_public, Вы писали:

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


S>>1) Параметрически полиморфный компаратор — это нонсенс. Просто потому что он не нужен. Ключевое слово здесь "параметрический", что означает "для любого типа T". Нет смысла сравнивать величины конкретного типа методом, работающим для любого типа.


_>Ну вообще то смысл есть. Вот http://ru.cppreference.com/w/cpp/utility/functional/equal_to простейший пример.


Благодарю за приммер ad hoc полиморфизма.

Unless specialised, invokes operator== on type T.


_>P.S. То, что там всё инлайнится, наверное можно даже и не уточнять. )))

Можно. И то что если оператор == не определен, то и не скомпилится, тоже можно не уточнять.
Re[14]: «Собаку съел»
От: alex_public  
Дата: 23.01.17 19:25
Оценка:
Здравствуйте, samius, Вы писали:

S>>>1) Параметрически полиморфный компаратор — это нонсенс. Просто потому что он не нужен. Ключевое слово здесь "параметрический", что означает "для любого типа T". Нет смысла сравнивать величины конкретного типа методом, работающим для любого типа.

_>>Ну вообще то смысл есть. Вот http://ru.cppreference.com/w/cpp/utility/functional/equal_to простейший пример.
S>Благодарю за приммер ad hoc полиморфизма.
S>

S>Unless specialised, invokes operator== on type T.


Нет, через ad hoc полиморфизм реализован оператор равенства. А у std::equal_to никаких перегрузок нет.

_>>P.S. То, что там всё инлайнится, наверное можно даже и не уточнять. )))

S>Можно. И то что если оператор == не определен, то и не скомпилится, тоже можно не уточнять.

Ну так это же тоже только плюс. )
Re[58]: «Собаку съел»
От: AlexRK  
Дата: 23.01.17 19:29
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Восхищаюсь твоим терпением, реально. ))


+1

Поражен терпением и спокойствием samius.
Re[13]: «Собаку съел»
От: vdimas Россия  
Дата: 23.01.17 22:36
Оценка: 3 (1)
Здравствуйте, Serginio1, Вы писали:

V>>Это то, что должен был генерить компилятор.

V>>Но приходится тебе.
S> А я уже в 1000 раз привожу ссылки где это делается
S>Optimising LINQ

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


S>Сейчас с развитием Рослина много оптимизаций на уровне Кода в CIL.


Я даже уверен, что с использованием Рослина можно накрутить свой собственный диалект C#, в котором попытаться порешать некоторые обсуждаемые вопросы. ))


S>Кроме того есть Net Native и там намного проще делать оптимизации из-за ограничения в рефлексии.


Оптимизации проще делать при отсутствии какой-либо рефлексии и конкретно нейтивность тут не при чём.
Просто не надо было тащить систему типов в VM, как это топорно сделала Java.

По-сути, Net Native — это совсем другая философия, это НЕ дотнет в его привычном понимании. ))

А в дотнет проблема была заложена изначально, ИМХО.
Он был разработан в то время, когда рост вычислительных мощностей удваивался каждые полтора года.
Отсюда такие случились такие акценты — на простоту инфраструктуры на основе топорной системы типов, типа джавистской.

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

ОК. С одной стороны это упростило первую версию точного GC, с другой стороны создало проблемы для оптимизаций.

Например, в С++ есть т.н. "бинарная склейка" одинаковых участков кода. Ну вот пусть совершенно разные типы после компиляции создадут идентичный бинарный код некоей ф-ии или метода — такой код будет склеен в единственный экземпляр. Именно это позволяет бороться с распуханием кода после применения шаблонов.

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

В общем, генерики дотнета сделали такими, какие они есть в том числе по этой причине — чтобы не плодить дубликаты практически одинакового кода в ходе специализаций. Идёт размен статического ресолвинга точных типов на динамические вызовы интерфейсов.

В общем, положа руку на — кошмар.

===============
Я более чем уверен, что концепция дотнета будет серьёзно пересматриваться.
Собсно уже. Ты правильно напомнил про Net Native. В любом сложном процессе важно целеполагание, на сегодня это целеполагание уже оформилось — это эффективный кроссплатформенный код.

Раньше целеполагание было чуть другим — дать простой в изучении и применении инструмент. А "эффективный и кроссплатформенный" — когда-нибудь потом. Декларировалось, что достаточно будет запустить имеющиеся приложения на новых версиях фреймворков и всё само собой случится. ))

Вот как раз из-за топорности системы типов VM нифига так и не случилось.
15 лет прошло уже... Дотнет набрал неимоверный вес и инерцию.
И при этом активно ПЕРЕДЕЛЫВАЕТСЯ прямо сейчас.
Сколько это еще займёт лет, как думаешь?

Думаю, еще десяток лет запросто, пока не откажутся окончательно от современной модели VM. Текущую парадигму исполнения VM в лучшем случае оставят как эмулируемую для совместимости.
Re[15]: «Собаку съел»
От: samius Япония http://sams-tricks.blogspot.com
Дата: 24.01.17 03:58
Оценка:
Здравствуйте, alex_public, Вы писали:

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


_>>>Ну вообще то смысл есть. Вот http://ru.cppreference.com/w/cpp/utility/functional/equal_to простейший пример.

S>>Благодарю за приммер ad hoc полиморфизма.
S>>

S>>Unless specialised, invokes operator== on type T.


_>Нет, через ad hoc полиморфизм реализован оператор равенства. А у std::equal_to никаких перегрузок нет.

Мне кажется что параметрический полиморфизм от ad hoc отличается не наличием перегрузок, а тем, что один код работает для всех типов без необходимости указания частных случаев. А вот каким образом подаются частные случаи, через перегрузку или специализацию шаблона — вопрос вторичный.
equal_to работает ровно для того же количества типов, что и оператор == (если не рассматривать случаи специализации шаблона для него, что явно отсылает к ad hoc полиморфизму). Таким образом, он является просто адаптацией оператора == к виду binary_function. Раз оператор == есть ad-hoc полиморфизм, то equal_to определенный через него же и работающий на том же механизме (разрешению перегрузки функций) ровно с теми же типами (кроме возможности дополнительной специализации, см выше) — ровно тот же ad hoc полиморфизм, что и у ==.

Вот если определить equal_to через
bool operator()(const T &lhs, const T &rhs) const
{
    return false;
}

, тогда мы получим параметрический полиморфизм. Но смысл такого оператора вырождается.
Re[16]: «Собаку съел»
От: alex_public  
Дата: 24.01.17 08:26
Оценка:
Здравствуйте, samius, Вы писали:

_>>Нет, через ad hoc полиморфизм реализован оператор равенства. А у std::equal_to никаких перегрузок нет.

S>Мне кажется что параметрический полиморфизм от ad hoc отличается не наличием перегрузок, а тем, что один код работает для всех типов без необходимости указания частных случаев. А вот каким образом подаются частные случаи, через перегрузку или специализацию шаблона — вопрос вторичный.

Безусловно. Поэтому если мы будем говорить о коде, реализованном на базе механизма явной специализации шаблонов (http://en.cppreference.com/w/cpp/language/template_specialization), то это будет именно ad hoc полиморфизм. Это механизм конечно же тоже широко применяется в C++ коде, но до распространённости классического применения шаблонов ему очень далеко.

Если же говорить о классическом применение шаблонов (типа контейнеров STL), то для программиста это безусловно является параметрическим полиморфизмом. Хотя бы потому, что программист пишет ровно одну версию кода для всех типов. А то, что компилятор там потом из соображений оптимизации может размножать эти версии кода, это уже дело десятое и на структуру кода не влияет. Это кстати можно легко увидеть с помощью простейшего мысленного эксперимента: если допустим поменять компилятор C++ так, чтобы он реализовывал шаблоны например по механизму параметрического полиморфизма Хаскеля, то весь классический шаблонный код продолжит спокойно работать без всяких изменений (ну разве что медленным станет, как Хаскель).

S>equal_to работает ровно для того же количества типов, что и оператор == (если не рассматривать случаи специализации шаблона для него, что явно отсылает к ad hoc полиморфизму). Таким образом, он является просто адаптацией оператора == к виду binary_function. Раз оператор == есть ad-hoc полиморфизм, то equal_to определенный через него же и работающий на том же механизме (разрешению перегрузки функций) ровно с теми же типами (кроме возможности дополнительной специализации, см выше) — ровно тот же ad hoc полиморфизм, что и у ==.


Конечно же equal_to является всего лишь обёрткой вокруг оператора равенства, предназначенная для более удобной и краткой передачи данного простейшего предиката в различные алгоритмы библиотеки. Но сам факт возможности написания данной обёртки является очевидным проявлением работы механизма параметрического полиморфизма.

S>Вот если определить equal_to через

S>
S>bool operator()(const T &lhs, const T &rhs) const
S>{
S>    return false;
S>}
S>

S>, тогда мы получим параметрический полиморфизм. Но смысл такого оператора вырождается.

Если очень хочется увидеть подобный компаратор, не являющийся просто обёрткой вокруг какого-то одного оператора, а привносящий какую-то логику, то есть варианты гораздо проще. Например так:
bool operator()(const T &lhs, const T &rhs) const
{
    return lhs.compare(rhs)==0;
}

Но на самом деле все эти дополнительные доказательства уже не нужны, т.к. уже та самая простейшая обёртка является очевидным представителем параметрического полиморфизма — работает для многих типов и при этом в исходных кодах ровно одна реализация.

И так, подводя итоги:
1. equal_to — компаратор.
2. работает с разными типами — полиморфный.
3. имеет одну реализацию для всех типов — параметрический.
4. реализован через шаблоны — инлайнится.
5. находится в стандартной библиотеке языка — нужен.


P.S. Ну а вообще я конечно не совсем корректно влез со своим C++ в вашу дискуссию. Вы то говорили про C# и там все твои аргументы были безусловно верными.
Re[14]: Бинарная склейка
От: Qbit86 Кипр
Дата: 24.01.17 09:37
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Именно это позволяет бороться с распуханием кода после применения шаблонов.


И насколько успешно позволяет?

Например, начнём с такой единицы трансляции, состоящей только из подключения заголовочных файлов:
#include <array>
#include <cstdint>


Потом постепенно добавляем explicit instance'ы каких-нибудь шаблонных классов, и компилируем:
#include <array>
#include <cstdint>

template class std::array<std::uint8_t, 5>;


#include <array>
#include <cstdint>

template class std::array<std::uint8_t, 5>;
template class std::array<double, 7>;


#include <array>
#include <cstdint>

template class std::array<std::uint8_t, 5>;
template class std::array<double, 7>;
template class std::array<std::array<double, 7>, 11>;


Какой тут будет выигрыш от указанной оптимизации, и как его задетектить?
Глаза у меня добрые, но рубашка — смирительная!
Re[14]: «Собаку съел»
От: Sinix  
Дата: 24.01.17 11:07
Оценка: +2
Здравствуйте, vdimas, Вы писали:

V>Почему топорной? Потому что рефлексируется всё и вся, включая приватные члены. Т.е., "как слышится, так и пишется" и ничего не "сокращается в уме". То бишь, система типов не позволяет никакой их редукции и никакого "стирания" артефактов типов вплоть до аж рантайма. Нифига себе... ))


V>ОК. С одной стороны это упростило первую версию точного GC, с другой стороны создало проблемы для оптимизаций.


Бинго! На этом посте имхо и стоит закрыть эту тему. Потому что вы 777 778 постов пережёвываете две мысли:
"с соблюдением _всех_ контрактов современного фреймворка часть оптимизаций практически невозможна"
и
"с отказом от части контрактов в плане оптимизаций дотнет принципиально ничем не отличается от нативного кода".
Причём с ними согласны все стороны, вы их просто повторяете друг другу. Заело

Особый юмор ситуации в том, что вторая мысль проверена практикой уже несколько лет как. Приложения под WP 8 — managed с прекомпиляцией. Почти все встроенные метро-приложения Win 10 — шарп + .net native. нетормозят™.


Вопрос по сути в следующем:
* когда аналог .native будет доступен для прочих форков дотнета (ориентировочно — через релиз).
* когда по качеству оптимизации транслированный код будет выигрывать у выхлопа JIT-а (ещё позднее).

Собственно всё.
Отредактировано 24.01.2017 11:08 Sinix . Предыдущая версия .
Re[15]: «Собаку съел»
От: vdimas Россия  
Дата: 24.01.17 14:29
Оценка: 2 (1)
Здравствуйте, Sinix, Вы писали:

S>"с соблюдением _всех_ контрактов современного фреймворка часть оптимизаций практически невозможна"


Да.

S>"с отказом от части контрактов в плане оптимизаций дотнет принципиально ничем не отличается от нативного кода".


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

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

А будет ли затем этот переносимый код пре-джиттен в родной (т.е. в тот самый нейтивный образ конкретного процессора ) — да абсолютно не принципиально. Львиная доля агрессивных оптимизаций при отказе от соблюдения приватных контрактов уровня исходника (вплоть до сохранения разметки памяти) может быть выполнена еще на стадии управляемого кода.

Собсно, принципиальное отличие проталкиваемой VM от гугла для веба — в этом и ни в чем более.

Ну и правила верификации тоже можно дорабатывать. Например, в стековой архитектуре удобно делать так, чтобы состояние стека после вызова одной процедуры автоматом являлось состоянием стека после помещения в него аргументов для вызова следующей процедуры. Вот этот момент — это то, почему в своё время программы на Форте умудрялись быть заметно шустрее программ, написанных на С.

Так вот, в нынешней реализации дотнетной VM каждый метод должен возвращать указатель стека к исходной точке к концу метода по всем своим веткам. Если предположить, что оптимизатор "видит", что некий приватный код вызывается из вполне счетного кол-ва мест и нет никакой возможности вызывать этот код извне, то для такого кода сие правило уже НЕ является необходимым. Тут уже можно начать оптимизировать — жонглировать порядком аргументов в стеке и самим способом работы со стеком.

Ну и, С++ тоже ограничен в плане редукций — для целей совместимости различные компиляторы ничего не делают даже с приватными полями, т.е. никак не оперируют с исходной разметкой памяти. Такая разметка детерминирована прямо в стандарте, ес-но. И этот больной мозоль тоже периодически обсасывают, бо выходит так, что в обозримой перспективе у нас есть лишь оптимизация/редукция только кода, но не данных+кода. А последнее мощнее на порядки. Сейчас оптимизатор С++ редуцирует промежуточные данные только в том случае, если видит их полный жизненный цикл. Но это своего рода тупик. Именно поэтому я одно время, скажем так, был весьма мотивирован на изучение низкоуровневой механики дотнета и пытался увидеть, к чему всё идёт. К сожалению, первые 8 лет — вообще не туда. Дотнет был разработан полупрофессиональными программистами, полуинженерами. Почти нубами. Это не попытка наезда, это медицинский факт. Эти люди получили почти безграничный кредит доверия на волне той самой шумихи "ява в интернете". Они оказались неспособны рассмотреть вопросы организации вычислений в комплексе, не смогли промоделировать реальные пути развития вычислительных сугубо программных технологий. Сам проект дотнета "выстрелил" лишь благодаря фантастическим потраченным на проект человекочасам в сочетании с, скажем прямо, недостижимым авторитетом MS на начало 2000-х.


S>Причём с ними согласны все стороны, вы их просто повторяете друг другу. Заело


Тут я могу согласиться лишь с тем, что любой спор в стиле "или всё или ничего" чаще всего бесполезен.
Но здесь не тот случай.


S>Особый юмор ситуации в том, что вторая мысль проверена практикой уже несколько лет как.


Что немного сбивает с толку, верно?
Т.е., когда дают ответ сразу, без демонстрации хода решения, то сгоряча можно принять теорему за аксиому. ))

В общем, тут примерно такой ход событий:
— управляемые среды призваны были обеспечить безопасность бинарника на уровне операционки (несколько проектов на Бартоке — это именно в эту сторону копание);
— результатом исследовательских работ явилось понимание невозможности перепрыгнуть на такой подход всей индустрией здесь и сейчас; тем более, что эти работы начинались в эпоху расцвета десктопа и бурного роста его выч.характеристик, а завершились в эпоху серьезного отката назад по этим же характеристикам из-за смещения акцента на мобильные/встраиваемые устройства;
— в этой ситуации более реальной для здесь и сейчас показалась схема оффлайн-компиляции с последующим распространением бинарников через доверенные источники.

Последнее — ключевое. Функции обеспечения "доверенности" выносятся из каждого экземпляра пользовательской ОС и переносятся на некую внешнюю, по отношению к ОС, инфраструктуру.


S>Приложения под WP 8 — managed с прекомпиляцией. Почти все встроенные метро-приложения Win 10 — шарп + .net native. нетормозят™.


Да. Поставляемые из доверенного источника, заметь. Конкретное устройство не мучается над вопросом верификации кода, а получает на него готовый ответ. А верифицируется в этой схеме лишь слой транспорта (и всё вокруг него), по которому готовый ответ доставляется до устройства.


S>Вопрос по сути в следующем:

S>* когда аналог .native будет доступен для прочих форков дотнета (ориентировочно — через релиз).

Это текущие рабочие моменты и не более того.
Т.е. акцент де-факто сместился — ОК, в первую очередь надо по-бырому переделать инфраструктуру.


S>* когда по качеству оптимизации транслированный код будет выигрывать у выхлопа JIT-а (ещё позднее).


А вот это тогда, когда перейдут на принципиально другую VM. Собсно, унутре майкрософтных оптимизирующих продуктов есть промежуточное представление навроде LLVM.

Более того, с выпуском VS 15 они теперь могут поддерживать оптимизацию байт-кода LLVM. Т.е. уже был сделан некий шаг по абстрагированию наработок оптимизаций от частностей базовой выч.архитектуры для исходного байткода (угу, в этом месте байткод — лишь "исходник"). Вангую, что наработки из разных областей будут топливом для развития именно этих моментов. Всё-таки, в плане агрессивной оптимизации программ, MS является одним из лидеров индустрии (или даже абсолютным лидером, я 3 года назад плотно гонял коммерческий компилятор от интел в сравнении с MS под винды — результаты MS часто были заметно лучше).
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.