Здравствуйте, _FRED_, Вы писали:
_FR>Конечно: SRP, "Разделяй и влавствуй" и прочее и прочее — две функции, каждая из которых решает какую-то одну маленькую задачу лучше чем одна, решающая две две, что первые можно комбинировать. Вот пример — сколько у тебя сейчас перегрузок ForEach? Допустим, две:
Пример с ForEach не есть на нарушение SRP. Выполнить действие Х по условию У — это одна задача в императивном мире. Попробуй *все* функции на шарпе писать так, как ты предлагаешь, делая действия максимально атомарными, и огребешь кучу проблем — это с императивными-то функциями.
А ты сейчас принципы функционального программирования — атомарные ф-ции и все такое — пытаешься наложить на императивное. ForEach — не функционален. А разговор на самом деле идет о том, какой синтаксис использовать для его вызова
_FR>
_FR>Но вот у меня есть ещё варианты ForEach, передающие в Action два параметра — элемент и его индекс. Тебе, что бы этого добиться и поддржать согласованость API придётся добавить две перегрузки: _FR>
Операции над наборами производятся разные, поэтому "объединять" наборы, ИМХО, не нужно.
".ToList()" только для ".ForEach" ИМХО, перебор — или пользоваться своим "ForEach<T>(IEnumerable<T>…" или foreach — это зависит от того, как ты трактуешь Тору…, нет, Липперта
Help will always be given at Hogwarts to those who ask for it.
Так как Where есть стандартный. И когда понадобится добавить что-то ещё в сигнатуру вызова, у меня и добавляется столько методов, сколько изменений требуется, а в твоём случае — приходится умножать на два.
Help will always be given at Hogwarts to those who ask for it.
Re[2]: LINQ & Except
От:
Аноним
Дата:
11.06.09 09:29
Оценка:
Здравствуйте, Sinix, Вы писали:
S>Во-первых используем HashSet.
А зачем? Except внутри и сам использует Set (который hash):
[CompilerGenerated]
private sealed class <ExceptIterator>d__92<TSource> : IEnumerable<TSource>, IEnumerable, IEnumerator<TSource>, IEnumerator, IDisposable
{
// Fieldsprivate int <>1__state;
private TSource <>2__current;
public IEqualityComparer<TSource> <>3__comparer;
public IEnumerable<TSource> <>3__first;
public IEnumerable<TSource> <>3__second;
public IEnumerator<TSource> <>7__wrap95;
private int <>l__initialThreadId;
public TSource <element>5__94;
public Set<TSource> <set>5__93;public IEqualityComparer<TSource> comparer;
...
...
}
Здравствуйте, _FRED_, Вы писали:
_FR>Так как Where есть стандартный. И когда понадобится добавить что-то ещё в сигнатуру вызова, у меня и добавляется столько методов, сколько изменений требуется, а в твоём случае — приходится умножать на два.
Хорошо, а с чем боремся-то? Сократить кол-во функций любой ценой? Так ты же говорил, что функции должны быть атомарными, что их будет много и так далее.
Потом на самом деле в моем случае придется делать перегрузки одной функции, а в твоем, если уж честно рассматривать разнообразные сценарии, двух. И преимущество опять-таки непонятно.
Тут основная претензия ко мне — это что я предлагаю использовать функциональный стиль для императивного кода. С чем я и не спорю. Ты же на самом деле идешь еще дальше и предлагаешь принципы написания функционального кода использовать для императивного
А проблема-то на самом деле уходит корнями в тот факт, что нам предложили красивый и модный синтаксис для выборок, а вот для изменений, которые как бы не менее редкие, не предложили. Что особенно явно и чувствуется на примере какого-нибудь linq2sql. Недаром товарищи вроде ИТ да Влада бьются как бы эти самые лямбды к инсертам да апдейтам прикрутить, используя весьма функциональный синтаксис для весьма, надо сказать, императивных действий. И да, с одной стороны, неправильно это, о чем я сам, кстати, и говорил А с другой стороны — что делать? То, что ты предлагаешь — это тоже не вариант. Это вообще франкейнштейн какой-то.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Здравствуйте, Ziggi111, Вы писали:
Z>>ИМХО Z>>
Z>>list.ForEach(x => DoSmth(x), x => Condition(x));
Z>>
Z>>читается не лучше, но, как и сказано в указанном блоге, недебагебелбно
ВВ>Это в блоге "недебагебелбно" У меня-то все дебагебельно — код в соседней сборке лежит
ага... и на каждый ForEach туда падает... чудо а не дебаг...
я не против такой реализации, сам так иногда делаю, но в какой-то момент понял, что Липперт прав
Здравствуйте, Воронков Василий, Вы писали:
_FR>>Так как Where есть стандартный. И когда понадобится добавить что-то ещё в сигнатуру вызова, у меня и добавляется столько методов, сколько изменений требуется, а в твоём случае — приходится умножать на два.
ВВ>Хорошо, а с чем боремся-то? Сократить кол-во функций любой ценой?
Не "любой", а просто "Сократить кол-во функций".
ВВ>Так ты же говорил, что функции должны быть атомарными, что их будет много и так далее.
Что их _может быть_ много. Когда каждая выполняет строго одну задачу, мы можем справляться с необходимостью расширения функционала с посредством комбинирования. В твоём же случае и _лишним_ параметром-предикатом это приводит к дублированию.
ВВ>Потом на самом деле в моем случае придется делать перегрузки одной функции, а в твоем, если уж честно рассматривать разнообразные сценарии, двух. И преимущество опять-таки непонятно.
Как так? Давай говорить не-абстрактно: покажи сигнатуры всех твохи перегрузок ForEach? У меня их всего две (здесь
).
ВВ>Тут основная претензия ко мне — это что я предлагаю использовать функциональный стиль для императивного кода. С чем я и не спорю. Ты же на самом деле идешь еще дальше и предлагаешь принципы написания функционального кода использовать для императивного
То, что я предлагаю называется функциональной декомпозицией и к "функциональному стилю" отношения не имеет никакого, поскольку применима в любом стиле программирования (при наличии подпрограмм).
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, Ziaw, Вы писали:
_FR>> Расскажи пожалуйста о преимуществах Where в данном конкретном примере над if. Z>Наглядность, мы сразу видим, что идем по отфильтрованному списку.
Здесь кто-то не видит, что мы "идем по отфильтрованному списку"?
list.Where(Condition).ForEach(DoSmth);
Z>В случае с if нам нужно: Z>1. Увидеть паттерн foreach/if Z>2. Понять, что условие там зависит только от элемента Z>Два действия вместо одного.
Как контр-аргумент могу привести непригодность к рефакторингу варианта c Where — если понадобится как-то особым образом обработать элементы, не удовлетворяющие условию, придётся писать больше кода, нежели в случае, если бы if стоял бы внутри for.
С другой стороны, все эти "Наглядность, Увидеть, Понять" как раз попадают под слова
…такая возможность ничего не добавляет к выразительности языка…
И … даже труднее… отладить, а еще она добавляет семантику замыкания, потенциально внося тонкие изменения в жизненные циклы объектов
…Когда мы предоставляем два почти одинаковых способа сделать в точности одну вещь, мы вносим сумятицу в индустрию, мы затрудняем людям чтение кода друг друга, и так далее
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Здесь кто-то не видит, что мы "идем по отфильтрованному списку"? _FR>
list.Where(Condition).ForEach(DoSmth);
Здесь вообще нет уверенности что мы идем по нему. =) linq ленив.
_FR>Как контр-аргумент могу привести непригодность к рефакторингу варианта c Where — если понадобится как-то особым образом обработать элементы, не удовлетворяющие условию, придётся писать больше кода, нежели в случае, если бы if стоял бы внутри for.
Да нет никакой обработки во Where(), есть только выборка. Если нам нужно обработать все — нам не нужно Where вообще. Два разных подхода — выбрать то что нужно (функция, результат на ладони, можно вызвать сколько угодно раз, может быть ленива) и обработать (действие, должно быть выполнено один и только один раз, результат за кадром).
Функциональный стиль отлично работает и естественно смотрится в выборке и плохо в обработке.
Здравствуйте, Ziaw, Вы писали:
_FR>>Здесь кто-то не видит, что мы "идем по отфильтрованному списку"? _FR>>
list.Where(Condition).ForEach(DoSmth);
Z>Здесь вообще нет уверенности что мы идем по нему. =) linq ленив.
При чём здесь linq? метод Where осуществляет выборку, ForEach — действие.
_FR>>Как контр-аргумент могу привести непригодность к рефакторингу варианта c Where — если понадобится как-то особым образом обработать элементы, не удовлетворяющие условию, придётся писать больше кода, нежели в случае, если бы if стоял бы внутри for.
Z>Да нет никакой обработки во Where(), есть только выборка.
Я нигде и не говорил, про обработку "во Where()". Прочитай пожалуйста внимательнее.
Z>Если нам нужно обработать все — нам не нужно Where вообще.
Я говорил о том, что если нам понадобится как-то обработать то, что не прошло через Where() то переписывать придётся больше, чем в случае с if.
Z>Два разных подхода — выбрать то что нужно (функция, результат на ладони, можно вызвать сколько угодно раз, может быть ленива) и обработать (действие, должно быть выполнено один и только один раз, результат за кадром). Z>Функциональный стиль отлично работает и естественно смотрится в выборке и плохо в обработке.
Какое это имеет отношение к тому, что я написал?
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>То, что я предлагаю называется функциональной декомпозицией и к "функциональному стилю" отношения не имеет никакого, поскольку применима в любом стиле программирования (при наличии подпрограмм).
Да ты что? Давай тогда быть последовательными, товарищ. Как ты производишь замену внутри строки, чтобы была "функциональная декомпозиция" и не было "нарушения SRP"?
Здравствуйте, Ziggi111, Вы писали:
ВВ>>Это в блоге "недебагебелбно" У меня-то все дебагебельно — код в соседней сборке лежит Z>ага... и на каждый ForEach туда падает...
Куда падает? Я дебажить буду саму реализацию ф-ции ForEach.
Z>чудо а не дебаг...
А Линк вы как дебажите? Ровно та же проблема.
Z>я не против такой реализации, сам так иногда делаю, но в какой-то момент понял, что Липперт прав
Ну правильно, они прикрутили к бабе яйца, а теперь же надо какие-то рекомендации для народа придумывать. Типа в этой позе можно, а в этой уже... эээ... "неженственно". А что они раньше-то думали?
Здравствуйте, Воронков Василий, Вы писали:
_FR>>То, что я предлагаю называется функциональной декомпозицией и к "функциональному стилю" отношения не имеет никакого, поскольку применима в любом стиле программирования (при наличии подпрограмм).
ВВ>Да ты что? Давай тогда быть последовательными, товарищ.
Давайте не будем уходить в сторону абсурда, Уважаемый. Я лишь сказал Вам, что неплохо бы выкинуть нафик один из параметров Вашего метода ибо он не нужен. Учить Вас писать код и производить с Вами замены в строчках мне ни сколечки не улыбается, с SRP или без оного.
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
_FR>Давайте не будем уходить в сторону абсурда, Уважаемый. Я лишь сказал Вам, что неплохо бы выкинуть нафик один из параметров Вашего метода ибо он не нужен. Учить Вас писать код и производить с Вами замены в строчках мне ни сколечки не улыбается, с SRP или без оного.
Лучше ты сам научись, как писать код, а не рассуждать о высоких материях. Посмотрел бы я на код реальных проектов, написанный с подобных позиций и на то, как хорошо он работает.
String.Replace ему не нравится видите ли, так нарушение же single responsibility — и ищем, и заменяем.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Спасибо, я читаю по-английски.
Видимо стоило, все-таки по русски. Ну ладно, я разжую. Аргументов там два, и оба отличаются от того, который ты нашел:
1. Речь не о том, что функционально это или нет, а о том, что вся работа с последовательностями дизайнилась в функциональном стиле, а такой метод этот стиль нарушает. Иными словами, такой вариант противоречит дизайну языка, не важно какой сам по себе дизайн, функциональный или не очень. И там подробно разжевано почему.
2. Выразительности такой код не добавит, а наоборот, запутает и, плюс к этому, "добавляет семантику замыкания, потенциально внося тонкие изменения в жизненные циклы объектов." То есть, реально, такой метод ухудшает имеющийся оператор foreach, добавляя малопредсказуемые побочные эффекты.
И при всем при этом, совершенно непонятно какую выгоду такое расширение может принести — полторы строчки кода, это не серьезно, тем более, что почти такого же эффекта можно добиться стандартными средствами.
Резюме: При кажущейся простоте, такой метод не предоставляя реальных преимуществ затрудняет понимание кода и способен привести к малопредсказуемым побочным эффектам.
Здравствуйте, IB, Вы писали:
ВВ>>Спасибо, я читаю по-английски. IB>Видимо стоило, все-таки по русски. Ну ладно, я разжую. Аргументов там два, и оба отличаются от того, который ты нашел:
IB>1. Речь не о том, что функционально это или нет, а о том, что вся работа с последовательностями дизайнилась в функциональном стиле, а такой метод этот стиль нарушает. Иными словами, такой вариант противоречит дизайну языка, не важно какой сам по себе дизайн, функциональный или не очень. И там подробно разжевано почему.
При чём здесь "дизайн языка", когда речь о библиотечном методе? Слова были о дизайне библиотеки, о том, что данные метод плохо бы смотрелся среди других методов.
Я вижу слова "Я философски против предоставления такого метода по двум причинам." и не вижу "наличия". Да и в любом случае — мнение, высказаное в блоге является личным мнением Эрика или мнением команды, разрабатывавшей System.Core. Я не вижу ответа в тексте блога на вопрос "почему плохо в своём коде иметь такой метод". Всё, что можно понять — это рекомендации основанные на том, что "добавляет семантику замыкания" (1), "труднее понять" (2) и "труднее … отладить" (3).
По пунктам:
1. никто не заставляет пользоваться замыканиями, так что данное обоснование кажется надуманным. Ведь никто же не запрещает использовать замыкания и side effects в методах, передаваемых в Select или Where.
2. Это вопрос самый спорный. Например варианты здесь
Some1();
for(var x in yy) {
// … сотня-другая итераций
}//fir
Some2();
когда меня не интересуют внутренности работы цикла (требуется от Some1 перейти к Some2). Отладчик не умеет "перепрагивать" через цикл и приходится ставить специальный breakpoint к Some2(); и перепрыгивать цикл самому.
IB>И при всем при этом, совершенно непонятно какую выгоду такое расширение может принести — полторы строчки кода, это не серьезно, тем более, что почти такого же эффекта можно добиться стандартными средствами.
Использование одной строчки там, где в другом случае нужно много больше. (здесь
)
IB>Резюме: При кажущейся простоте, такой метод не предоставляя реальных преимуществ
Для стандартной библиотеки — да. Точно так же можно предать анафеме хелперы типа такого. Без ниже прекрасно можно обойтись. Но с ними лучше.
IB>…затрудняет понимание кода и способен привести к малопредсказуемым побочным эффектам.
Мне кажется, что этих эффектом можно добиться и без ForEach. Одновременно с этим, с ForEach можно этих же эффектов избежать. И причина возникновения эффектов не в ForEach, а в содержимом черепной коробки
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, IB, Вы писали:
IB>Видимо стоило, все-таки по русски.
Знаешь, "по-русски" я бы тебе давно уже объяснил, что я думаю о подобных гайдлайнах — да боюсь забанят.
IB>1. Речь не о том, что функционально это или нет, а о том, что вся работа с последовательностями дизайнилась в функциональном стиле, а такой метод этот стиль нарушает.
*Вся* работа с последовательностями ли, с базой данных и пр. уж никак не может вестись в одном стиле, о чем уже так долго говорят большевики и с чем, видимо, придется смириться.
А в данном случае непонятно — откуда возникает требование этого функционального стиля? Если передо мной стоят задачи модификации или, не дай бог, появляются методы имеющие сохраняемое состояние — то причем здесь вообще функциональный стиль? И почему это должно быть функционально, если в действительности это не функционально ни на йоту?
Это мы только ForEach<> касаемся, а можно еще и рассмотреть всякие Aggregate<> — там ведь вообще ужас с этой точки зрения.
Да, и я уже приводил этот пример.
String.Replace — очень схожая задача с обсуждаемой здесь. И совершенно нефункционально. И при этом самая что ни на есть последовательность. В каком стиле предлагаете проводить замену?
IB>Иными словами, такой вариант противоречит дизайну языка, не важно какой сам по себе дизайн, функциональный или не очень. И там подробно разжевано почему.
Дизайну Шарпа противоречит императивный стиль?
Функциональному дизайну Линка, который здесь вообще не причем, противоречит императивный стиль?
Вам дали библиотеку со "спецэффектами" и теперь уже стиль у языка другой?
IB>2. Выразительности такой код не добавит, а наоборот, запутает и, плюс к этому, "добавляет семантику замыкания, потенциально внося тонкие изменения в жизненные циклы объектов." То есть, реально, такой метод ухудшает имеющийся оператор foreach, добавляя малопредсказуемые побочные эффекты.
То же самое можно сказать и про Where по сравнению с foreach.
IB>И при всем при этом, совершенно непонятно какую выгоду такое расширение может принести — полторы строчки кода, это не серьезно, тем более, что почти такого же эффекта можно добиться стандартными средствами. IB>Резюме: При кажущейся простоте, такой метод не предоставляя реальных преимуществ затрудняет понимание кода и способен привести к малопредсказуемым побочным эффектам.
Именно так говорят люди, когда не хотят пересаживаться с фор-ичей на Линк