Re[2]: Несколько соображений по дизайну C#
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 12.07.16 07:52
Оценка: +2
Здравствуйте, nikov, Вы писали:

G>>В языке много бессмысленных ритуалов, например после каждой строчки нужно ставить ;. Обязательно. Вопрос зачем?

G>>Еще один ритуал. При вызове функции обязательно нужно ставить (). Даже если функция не является мутатором.

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


Люди не машины. Эти мелкие синтаксические особенности достаточно часто умудряются бить по самому глубинному (не в смысле эмоций, а в смысле склонностей, привычек, и т.п.)
The God is real, unless declared integer.
Re[2]: Несколько соображений по дизайну C#
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 12.07.16 08:54
Оценка: +3 :))
Здравствуйте, nikov, Вы писали:

N>Ну вот просто удивительно. У разных языков программирования есть столько существенных преимуществ и недостатков, а люди обсуждают незначительные детали синтаксиса.


Потому что в синтаксис на первый взгляд проще внести свой сверхценный вклад
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
AVK Blog
Re[2]: Несколько соображений по дизайну C#
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.07.16 08:57
Оценка:
Здравствуйте, romangr, Вы писали:
R>Не тем ты, по-моему, занят.
R>Мне бы, например, было интересно допиливание CLR в плане размещения объектов по месту.
R>Т.е. типа struct но с классами. Чтобы объекты внутри других объектов не ссылкой были а по месту. Атрибутами размечалось бы.
R>Профит — меньше нагрузка на GC, ну и всякие кэш-френдли в подарок.
типа боксинга наоборот — то есть встраивание reference-типа по месту?
Не представляю, как это можно было бы сделать. С боксингом как раз всё понятно — он порождает клон экземпляра, что работает т.к. у value-типов нет identity.
А вот с этим flattening-ом что делать?
Предположим, у нас есть flattened-поле типа MyNestedType внутри MyParentType:
public class MyParentType
{
public MyNestedType child = new MyNestedType();
}


И есть у нас где-то функция F, которая принимает MyNestedType:
public static void F(MyNestedType t)
{
  GC.Collect(); // Что мы делаем с тем объектом, на который ссылается t?
  return;
}

Что будет, если мы передадим в F то самое поле?
F((new MyParentType().child)?

Что должен сделать GC? В обычном CLR он трактует стек как GCRoot и спасает содержимое t.
В поправленном CLR t может указывать как на свободный объект, так и на flattened. В первом случае надо спасать t; во втором — надо спасать родителя.
Как отличить эти ситуации? Напомню — на момент вызова GC.Collect() ни одной живой ссылки на родителя нету.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Несколько соображений по дизайну C#
От: hardcase Пират http://nemerle.org
Дата: 12.07.16 09:05
Оценка:
Здравствуйте, Sinclair, Вы писали:

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

R>>Не тем ты, по-моему, занят.
R>>Мне бы, например, было интересно допиливание CLR в плане размещения объектов по месту.
R>>Т.е. типа struct но с классами. Чтобы объекты внутри других объектов не ссылкой были а по месту. Атрибутами размечалось бы.
R>>Профит — меньше нагрузка на GC, ну и всякие кэш-френдли в подарок.
S>типа боксинга наоборот — то есть встраивание reference-типа по месту?


Вероятно уважаемый romangr клонит в сторону region inference и stack allocation, но эти техники требуют неиллюзорных телодвижений от транслятора в код целевой платформы.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[7]: Несколько соображений по дизайну C#
От: Слава  
Дата: 12.07.16 09:12
Оценка: :)
Здравствуйте, Gattaka, Вы писали:

AVK>>Потому что метод без скобочек означает method group conversion.

G>Вывод можно сделать, даже если у метода есть перегрузки.

Вы помните, что такое "указатель на функцию" в Си? Вот именно такой синтакс для его получения, без скобочек.
Re[4]: Несколько соображений по дизайну C#
От: Sinclair Россия https://github.com/evilguest/
Дата: 12.07.16 10:44
Оценка: +1
Здравствуйте, hardcase, Вы писали:

H>Вероятно уважаемый romangr клонит в сторону region inference и stack allocation, но эти техники требуют неиллюзорных телодвижений от транслятора в код целевой платформы

Тогда при чём тут разметка атрибутами? Это ж вообще чистый JIT, PGO и прочий хотспоттинг, ортогональный собственно устройству MSIL и тем более C#.
Если всё же тема именно об этом, то мне интересно подсмотреть, каков ожидаемый выигрыш. В том смысле, что region inference и stack allocation важны там, где у нас нет value types (не будем показывать пальцем), и даже самые простые пользовательские типы вынуждены быть reference.
Вводя value types где уместно, мы уже получаем значительный performance gain, при этом без усложнения инфраструктуры. Сколько ещё мы наиграем за счёт инференса для типов, которые мы не можем превратить в value? На каких задачах это будет заметно?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Несколько соображений по дизайну C#
От: romangr Россия  
Дата: 13.07.16 10:25
Оценка:
Здравствуйте, hardcase, Вы писали:
H>Вероятно уважаемый romangr клонит в сторону region inference и stack allocation, но эти техники требуют неиллюзорных телодвижений от транслятора в код целевой платформы.

Нет, Синклер все правильно описал.
И проблемы тоже правильные озвучил.
Я могу ошибаться. Но ведь если ничего не предлагать, и развития же не будет?
Re[5]: Несколько соображений по дизайну C#
От: Sinix  
Дата: 13.07.16 12:04
Оценка: 111 (2)
Здравствуйте, Sinclair, Вы писали:

S>Вводя value types где уместно, мы уже получаем значительный performance gain, при этом без усложнения инфраструктуры. Сколько ещё мы наиграем за счёт инференса для типов, которые мы не можем превратить в value? На каких задачах это будет заметно?



Проверялось неоднократно. Выигрыш в основном для всякой инфраструктурщины типа проблем с IEnumerable в kestrel (пруфы с перфтестами). Для чистой синтетики выигрыш, понятное дело, в разы, на реальном коде — проценты.

Для JIT предлагаемая оптимизация спасает только в случае, когда время жизни объекта определяется видимостью локальной меременной (упрощаю, ага), это всё-таки не слишком частый случай.
С .Net Native всё конечно бодрее, но там и без этого работы — конь не валялся.

Ссылки:
https://github.com/dotnet/coreclr/issues/1784 (тикет)
http://xoofx.com/blog/2015/10/08/stackalloc-for-class-with-roslyn-and-coreclr/ (прототип)
(и ещё немножко магии от того же товарища http://xoofx.com/blog/2016/05/25/inline-il-asm-in-csharp-with-roslyn/)

ну и список прочих хотелок на ту же тему.
Re[5]: Несколько соображений по дизайну C#
От: Artem Korneev США https://www.linkedin.com/in/artemkorneev/
Дата: 14.07.16 17:50
Оценка:
Здравствуйте, Gattaka, Вы писали:

G>Да вы элементарно выставляете курсор на переменную и ее использование подсвечивается. Либо найти использования.


Столько телодвижений чтоб "сэкономить" на написании ключевого слова var?
var довольно легко распознаётся глазом чтоб увидеть места определения новых переменных и различать их от изменения уже существующих переменных.
С уважением, Artem Korneev.
Re: Несколько соображений по дизайну C#
От: Pzz Россия https://github.com/alexpevzner
Дата: 15.07.16 08:06
Оценка:
Здравствуйте, Gattaka, Вы писали:

G>В языке много бессмысленных ритуалов, например после каждой строчки нужно ставить ;. Обязательно. Вопрос зачем?


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

G>Еще один ритуал. При вызове функции обязательно нужно ставить (). Даже если функция не является мутатором. То есть выражение вида:


G>
G>var allIds = result.SelectMany(x => x).Distinct().ToList();
G>

G>Можно было бы переписать:
G>
G>var allIds = result.SelectMany.Distinct.ToList
G>


И как в месте использования понять, цепочка ли это вызовов функций или доступ к глубоко вложенному полю?

И второй вопрос. var fp = Function. Вы чего присваеваете fp, значение функции, или указатель на функцию? Или в C# нет указателей на функцию?

G>А если убрать обязательность var, то совсем здорово:

G>
G>allIds = result.SelectMany.Distinct.ToList
G>


Все-таки, присваивание должно как-то синтаксически отличаться от создания переменной с инициализацией и автовыводом типа. А то ошибетесь в одной букве, и вместо присваивания получите новую переменную. Причем при удачном выборе имени это будет трудно увидеть глазом.

G>Могло бы выглядеть как:

G>public class Some
G>{
G> public Some(int val1, int val2)
G> {
G> }
G>}

G>То есть наличие в конструкторе означает наличие у типа этих полей.

G>Что думаете? Есть ли основания у подобных претензий?

Т.е., чтобы понять, какие у класса есть поля, надо еще и все конструкторы просмотреть?
Re[5]: Несколько соображений по дизайну C#
От: Evgeny.Panasyuk Россия  
Дата: 15.07.16 12:49
Оценка: :)
Здравствуйте, Sinclair, Вы писали:

S>Вводя value types где уместно, мы уже получаем значительный performance gain, при этом без усложнения инфраструктуры.


В CodeJam в алгоритмах приходится отдельно обрабатывать reference/value типы, это и есть "усложнение инфраструктуры".

S>Сколько ещё мы наиграем за счёт инференса для типов, которые мы не можем превратить в value?


Например String в C# это class — для доступа к символу на ровном месте получаем двойную индирекцию.

S>На каких задачах это будет заметно?


На тех которые по большей части упираются во взаимодействие с памятью. Плюс во время GC.
Re[6]: Несколько соображений по дизайну C#
От: Sinix  
Дата: 15.07.16 13:47
Оценка: 28 (2) +1
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>В CodeJam в алгоритмах приходится отдельно обрабатывать reference/value типы, это и есть "усложнение инфраструктуры".

Если честно, там усложнизмы на ровном месте в куче мест емнип. Когда смотрел (ещё в марте), то большая часть кода могла быть переписана без кодогенерации и лишних перегрузок.

EP>Например String в C# это class — для доступа к символу на ровном месте получаем двойную индирекцию.

Не-не-не, для "матчасть не знаю и не хочу знать" у нас есть специально обученные люди, не надо так

Всё ок с внутренностями string, см стареющую классику (layout строк поменялся в 4.0 (ну и ещё пруф), да и StringBuilder тож заметно переколбашен, но who cares?)


S>>На каких задачах это будет заметно?

EP>На тех которые по большей части упираются во взаимодействие с памятью. Плюс во время GC.
+ избавление от virtual calls и инлайнинг кода, который позволяет сделать ещё больше оптимизаций. На практике оно конечно не так эффектно как в теории, но всё равно приятно.
Re[7]: Несколько соображений по дизайну C#
От: Evgeny.Panasyuk Россия  
Дата: 15.07.16 14:31
Оценка:
Здравствуйте, Sinix, Вы писали:

EP>>В CodeJam в алгоритмах приходится отдельно обрабатывать reference/value типы, это и есть "усложнение инфраструктуры".

S>Если честно, там усложнизмы на ровном месте в куче мест емнип. Когда смотрел (ещё в марте), то большая часть кода могла быть переписана без кодогенерации и лишних перегрузок.

Тут речь не про перегрузки и кодогенерацию, а про то что там разное поведение для reference/value type.

EP>>Например String в C# это class — для доступа к символу на ровном месте получаем двойную индирекцию.

S>Не-не-не, для "матчасть не знаю и не хочу знать" у нас есть специально обученные люди, не надо так

Точно, спасибо Так причём я когда писал сообщение код-то просмотрел, вот только неправильно его интерпретировал — я неверно предположил что m_firstChar там указатель, а тип не проверил

Тем не менее — как раз наглядный пример что это всё это таки стоит свеч, String ведь не единственный класс подобного рода.

S>>>На каких задачах это будет заметно?

EP>>На тех которые по большей части упираются во взаимодействие с памятью. Плюс во время GC.
S>+ избавление от virtual calls и инлайнинг кода, который позволяет сделать ещё больше оптимизаций. На практике оно конечно не так эффектно как в теории, но всё равно приятно.

Я так понимаю ещё и замыкания станут эффективней?
Re[8]: Несколько соображений по дизайну C#
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 15.07.16 14:43
Оценка: -1 :)
Здравствуйте, Evgeny.Panasyuk, Вы писали:

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


EP>>>В CodeJam в алгоритмах приходится отдельно обрабатывать reference/value типы, это и есть "усложнение инфраструктуры".

S>>Если честно, там усложнизмы на ровном месте в куче мест емнип. Когда смотрел (ещё в марте), то большая часть кода могла быть переписана без кодогенерации и лишних перегрузок.

EP>Тут речь не про перегрузки и кодогенерацию, а про то что там разное поведение для reference/value type.


Тебе уже кучу примеров привл например
http://rsdn.ru/forum/flame.comp/6497854.1
Автор: Serginio1
Дата: 11.07.16

Ты давай за свои слова отвечай про 100 раз и приводи реализацию

auto it = min_element(source, [](auto &i){ return i->value; });
и солнце б утром не вставало, когда бы не было меня
Re[8]: Несколько соображений по дизайну C#
От: Sinix  
Дата: 15.07.16 14:49
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Тут речь не про перегрузки и кодогенерацию, а про то что там разное поведение для reference/value type.

А это где такое чудо, напомни?

EP>Тем не менее — как раз наглядный пример что это всё это таки стоит свеч, String ведь не единственный класс подобного рода.

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

Ну и для каких других типов такое будет иметь смысл? Экзотика типа big integer/rational разве что. Для всего остального за глаза хватит структуры с массивом внутри, jit замечательно такие вещи инлайнит.
А для больших чисел опять-таки проще сделать полноценную поддержку со стороны платформы, чем пилить очередной всемогутор, который будет слишком навороченным для простых случаев и недостаточно гибким — для сложных.


S>>+ избавление от virtual calls и инлайнинг кода, который позволяет сделать ещё больше оптимизаций. На практике оно конечно не так эффектно как в теории, но всё равно приятно.

EP>Я так понимаю ещё и замыкания станут эффективней?
Ну как бы да, но для этого нужен инлайнинг делегатов, чего пока нет даже в планах, т.к. задача всё-таки сложная для JIT. Вот в .Net Native — поверю охотно. Только его пока допилят...
Re[9]: Несколько соображений по дизайну C#
От: Evgeny.Panasyuk Россия  
Дата: 15.07.16 15:04
Оценка: 8 (1)
Здравствуйте, Serginio1, Вы писали:

EP>>Тут речь не про перегрузки и кодогенерацию, а про то что там разное поведение для reference/value type.

S>Ты давай

Ты хочешь и эту тему зафлудить "алогичной кашей"?

S>за свои слова отвечай про 100 раз


Давай пруфлинк на "100 раз".

S>и приводи реализацию

S>
S>auto it = min_element(source, [](auto &i){ return i->value; });
S>


template<typename Range, typename Selector, typename Compare = std::less<>>
auto min_element(Range &&x, Selector selector, Compare compare = Compare{})
{
    using std::begin; using std::end;
    return min_element(begin(x), end(x), selector, compare);
}

Re[9]: Несколько соображений по дизайну C#
От: Evgeny.Panasyuk Россия  
Дата: 15.07.16 15:17
Оценка:
Здравствуйте, Sinix, Вы писали:

EP>>Тут речь не про перегрузки и кодогенерацию, а про то что там разное поведение для reference/value type.

S>А это где такое чудо, напомни?

Вот
Автор: Evgeny.Panasyuk
Дата: 23.03.16
— там два момента.

EP>>Тем не менее — как раз наглядный пример что это всё это таки стоит свеч, String ведь не единственный класс подобного рода.

S>ну да. Но тут есть маааленький нюанс: для того, чтоб эта оптимизация имела смысл, пришлось протащить знание о кишках string по всему CLR, от JIT и до профайлера.
S>Ну и для каких других типов такое будет иметь смысл?

Не прям такое, а уменьшение ветвления по памяти в общем.
То есть например есть класс, он агрегирует другие объекты других классов, те в свою очередь аггрегируют далее. Получается дерево. В большинстве случаев размазывать все под-объекты по памяти не требуется, и достаточно "плоского" "inline"-хранения. На C# структуры имеют ряд ограничений, и по факту многие под-объекты будут классами, даже те которые по смыслу могли быть "inline".
Re[10]: Несколько соображений по дизайну C#
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 15.07.16 16:24
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

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


EP>>>Тут речь не про перегрузки и кодогенерацию, а про то что там разное поведение для reference/value type.

S>>Ты давай

EP>Ты хочешь и эту тему зафлудить "алогичной кашей"?


S>>за свои слова отвечай про 100 раз


EP>Давай пруфлинк на "100 раз".


S>>и приводи реализацию

S>>
S>>auto it = min_element(source, [](auto &i){ return i->value; });
S>>


EP>
EP>template<typename Range, typename Selector, typename Compare = std::less<>>
EP>auto min_element(Range &&x, Selector selector, Compare compare = Compare{})
EP>{
EP>    using std::begin; using std::end;
EP>    return min_element(begin(x), end(x), selector, compare);
EP>}
EP>

EP>

Проверка на пустой список. Например после применения фильтров.
Проверка на null. В моем примере это все есть.

Развернем min_element. http://www.cplusplus.com/reference/algorithm/min_element/
Там селектора нет.

Можно еще поподробнее про typename Selector,
Просто я сейчас изучаю С++ но мне интересно как я могу применить. Или ссылочку на эту конструкцию

[](auto &i){ return i->value; }


И можно пояснить Compare{}. То есть шаблон std::less<>> должен применяться к типу селектора (i->value)

Ну и где 100 раз даже в этом усеченном варианте. Напомню, что я за то что C# в 2 раза медленнее С++ попросил прощения.
Не говорил ты тех слов. А вот насчет 100 раз ты говорил.

Ну и Sinix тебе опровержение твоих слов тоже привел
https://rsdn.ru/forum/dotnet/6506104.1
Автор: Sinix
Дата: 15.07.16
и солнце б утром не вставало, когда бы не было меня
Отредактировано 15.07.2016 16:45 Serginio1 . Предыдущая версия .
Re[10]: Несколько соображений по дизайну C#
От: Sinix  
Дата: 15.07.16 16:35
Оценка: 54 (2)
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Вот
Автор: Evgeny.Panasyuk
Дата: 23.03.16
— там два момента.


А, ну как и было сказано — иногда больше работы не значит лучше. Специально засёк время — 10 минут на код ушло. Блин, но оформление ответа больше потрачу, наверно
Для структур соотношение:
        Method |      Median |     StdDev | Scaled |         Min | Lnml(min) | Lnml(max) |         Max |
-------------- |------------ |----------- |------- |------------ |---------- |---------- |------------ |
    MinCodeJam |  13.5474 us |  4.2560 us |   1.00 |   9.8527 us |      1.00 |      1.00 |  57.8845 us |
      MinNaive | 133.8322 us | 37.9869 us |   9.88 | 109.2005 us |      9.78 |      9.78 | 584.1817 us |
         MinOk |  17.6527 us |  1.5569 us |   1.30 |  13.9580 us |      1.28 |      1.28 |  25.8633 us |
 MinOkComparer |  16.4211 us |  1.2513 us |   1.21 |  13.5474 us |      1.18 |      1.18 |  27.0949 us |
  MinDoneRight |   1.6421 us |  0.5551 us |   0.12 |   1.2316 us |      0.12 |      0.12 |  10.2632 us |


для строк:
        Method |        Median |      StdDev | Scaled |           Min | Lnml(min) | Lnml(max) |           Max |
-------------- |-------------- |------------ |------- |-------------- |---------- |---------- |-------------- |
    MinCodeJam |   331.7068 us |  19.2213 us |   1.00 |   289.4224 us |      1.00 |      1.00 |   419.9704 us |
      MinNaive | 4,391.0101 us | 622.1757 us |  13.24 | 2,497.2433 us |     12.18 |     12.18 | 5,005.5709 us |
         MinOk |    25.0422 us |   5.5940 us |   0.08 |    16.4211 us |      0.07 |      0.07 |    79.2320 us |
 MinOkComparer |   313.6436 us |  38.8401 us |   0.95 |   170.3692 us |      0.94 |      0.94 |   474.9812 us |
  MinDoneRight |   252.4749 us |  61.4753 us |   0.76 |   155.5902 us |      0.66 |      0.66 |   359.6227 us |


и собственно метод MinOkComparer :
        private static T MyMinByComparer<T, TValue>(IEnumerable<T> source, Func<T, TValue> selector)
        {
            var comparer = Comparer<TValue>.Default;
            T result = default(T);
            TValue resultValue = default(TValue);
            bool hasData = false;
            foreach (var item in source)
            {
                if (!hasData || comparer.Compare(resultValue, selector(item)) > 0)
                {
                    result = item;
                    resultValue = selector(item);
                    hasData = true;
                }
            }
            if (!hasData)
                throw new Exception("Bla-bla-bla");
            return result;
        }

на самом деле это уже второй вариант, первый — MinOk — рвал всех за счёт использования Operators<T>, которые не тупят и используют ordinal comparison. Ну ок, пришлось переделывать.

В чём подвох:
1. Тяп-ляп универсальный код, написанный без включения мозга оказался немного быстрее "оптимизированного" для ссылочных полей и на ~20% медленнее — для структур.
2. Не менее тяп-ляп код, написанный для конкретного частного случая выполняется на четверть быстрее для ссылочных полей и в 8 раз быстрее — для структур.

сравниваем, если что, с вот этим. 5000 строк неэффективной кодогенерации

  Перфтест
using System;
using System.Collections.Generic;
using System.Linq;

using CodeJam.Arithmetic;
using CodeJam.Collections;
using CodeJam.PerfTests;

using JetBrains.Annotations;

using NUnit.Framework;

using static CodeJam.AssemblyWideConfig;
using static CodeJam.PerfTests.CompetitionHelpers;

// ReSharper disable once CheckNamespace

namespace CodeJam
{
    [PublicAPI]
    [TestFixture(Category = PerfTestCategory + ": EnumHelper")]
    public class TempPerfTests
    {
        public class Data
        {
            public Data(int structField)
            {
                StructField = structField;
                StringField = structField.ToString();
            }

            public int StructField { get; }
            public string StringField { get; }
        }

        private static readonly Data[] _data = Enumerable
            .Range(1, 1000)
            .Select(i => new Data(i))
            .ToArray();

        private static T MyMinBy<T, TValue>(IEnumerable<T> source, Func<T, TValue> selector)
        {
            var greater = Operators<TValue>.GreaterThan;
            T result = default(T);
            TValue resultValue = default(TValue);
            bool hasData = false;
            foreach (var item in source)
            {
                if (!hasData || greater(resultValue, selector(item)))
                {
                    result = item;
                    resultValue = selector(item);
                    hasData = true;
                }
            }
            if (!hasData)
                throw new Exception("Bla-bla-bla");
            return result;
        }

        private static T MyMinByComparer<T, TValue>(IEnumerable<T> source, Func<T, TValue> selector)
        {
            var comparer = Comparer<TValue>.Default;
            T result = default(T);
            TValue resultValue = default(TValue);
            bool hasData = false;
            foreach (var item in source)
            {
                if (!hasData || comparer.Compare(resultValue, selector(item)) > 0)
                {
                    result = item;
                    resultValue = selector(item);
                    hasData = true;
                }
            }
            if (!hasData)
                throw new Exception("Bla-bla-bla");
            return result;
        }

        [Test]
        public void RunMinByIntCase() => Competition.Run<MinByIntCase>(RunConfig);

        public class MinByIntCase
        {
            [CompetitionBaseline]
            public Data MinCodeJam() => _data.MinBy(x => x.StructField);

            [CompetitionBenchmark(6.98, 15.66)]
            public Data MinNaive() => _data.OrderBy(x => x.StructField).FirstOrDefault();

            [CompetitionBenchmark(0.81, 1.67)]
            public Data MinOk() => MyMinBy(_data, x => x.StructField);

            [CompetitionBenchmark(0.83, 1.64)]
            public Data MinOkComparer() => MyMinByComparer(_data, x => x.StructField);

            [CompetitionBenchmark(0.07, 0.18)]
            public Data MinDoneRight()
            {
                Data result = null;
                int resultValue = 0;
                var local = _data;
                foreach (var other in local)
                {
                    if (result == null || resultValue > other.StructField)
                    {
                        result = other;
                        resultValue = other.StructField;
                    }
                }
                return result;
            }
        }

        [Test]
        public void RunMinByStringCase() => Competition.Run<MinByStringCase>(RunConfig);

        public class MinByStringCase
        {
            [CompetitionBaseline]
            public Data MinCodeJam() => _data.MinBy(x => x.StringField);

            [CompetitionBenchmark(8.46, 21.14)]
            public Data MinNaive() => _data.OrderBy(x => x.StringField).FirstOrDefault();

            [CompetitionBenchmark(0.05, 0.11)]
            public Data MinOk() => MyMinBy(_data, x => x.StringField);

            [CompetitionBenchmark(0.53, 1.33)]
            public Data MinOkComparer() => MyMinByComparer(_data, x => x.StringField);

            [CompetitionBenchmark(0.53, 0.86)]
            public Data MinDoneRight()
            {
                Data result = null;
                string resultValue = null;
                var local = _data;
                foreach (var other in local)
                {
                    if (result == null || string.Compare(resultValue, other.StringField) > 0)
                    {
                        result = other;
                        resultValue = other.StringField;
                    }
                }
                return result;
            }
        }
    }
}


В общем надо знать матчасть, думать, а затем писать. И мерять. Иначе вот такой вот неудобняк получается.

EP>Не прям такое, а уменьшение ветвления по памяти в общем.

EP>То есть например есть класс, он агрегирует другие объекты других классов, те в свою очередь аггрегируют далее. Получается дерево. В большинстве случаев размазывать все под-объекты по памяти не требуется, и достаточно "плоского" "inline"-хранения. На C# структуры имеют ряд ограничений, и по факту многие под-объекты будут классами, даже те которые по смыслу могли быть "inline".

Есть у меня подозрение, что достаточно передать ссылку на "вложенный" объект за пределы класса (или просто вытащить её рефлексией), чтобы обломать всю красоту.
Re[11]: Несколько соображений по дизайну C#
От: Evgeny.Panasyuk Россия  
Дата: 15.07.16 16:44
Оценка:
Здравствуйте, Sinix, Вы писали:

EP>>Вот
Автор: Evgeny.Panasyuk
Дата: 23.03.16
— там два момента.

S>А, ну как и было сказано — иногда больше работы не значит лучше.
S>Специально засёк время — 10 минут на код ушло. Блин, но оформление ответа больше потрачу, наверно
S>Для структур соотношение:

Мы же в данном контексте не производительность перегрузок и т.п. обсуждаем, а разную семантику reference/value, которую нужно обрабатывать отдельным кодом. Я ссылку привёл именно на ветку о семантике.

EP>>Не прям такое, а уменьшение ветвления по памяти в общем.

EP>>То есть например есть класс, он агрегирует другие объекты других классов, те в свою очередь аггрегируют далее. Получается дерево. В большинстве случаев размазывать все под-объекты по памяти не требуется, и достаточно "плоского" "inline"-хранения. На C# структуры имеют ряд ограничений, и по факту многие под-объекты будут классами, даже те которые по смыслу могли быть "inline".
S>Есть у меня подозрение, что достаточно передать ссылку на "вложенный" объект за пределы класса (или просто вытащить её рефлексией), чтобы обломать всю красоту.

Да, но я говорю о том что в большинстве случае ничего подобного не происходит.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.