Побочные эффекты в итераторе считаются вредными? - PullRequest
5 голосов
/ 26 ноября 2008

Сегодня я написал свой первый итератор C #. Woohoo.

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

Я пытался реализовать его как запрос LINQ, но на самом деле мне не нравился тот факт, что предикат для предложения where имеет побочные эффекты. Это определенный запах.

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

Но потом я вспомнил итераторы. И теперь у меня есть итератор, который возвращает действительные файлы и обрабатывает (перемещает) неверные.

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

Ответы [ 9 ]

4 голосов
/ 26 ноября 2008

Итераторы с побочными эффектами - БАД, ладно? :)

Если у вас есть последовательность, содержащая все файлы, вы можете иметь что-то visitor -ish, которое посещает все элементы и вызывает функцию для каждого случая. Различение в посетителе может быть либо предикатом, который вы можете предоставить, либо присущим посетителю.

Итак, я не говорю на C #, но что-то вроде этого псевдокода:

good_handler = new FileHandler() {
  handle(File f) { print "Yay!"; }
}

bad_handler = new FileHandler() {
  handle(File f) { print "Nay!"; }
}

files = YourFileSequence();
visitor = new Visitor(good_handler, bad_handler);
visitor.visit(files);
3 голосов
/ 26 ноября 2008

Я бы сказал, что обычно плохая идея иметь побочные эффекты в итераторе, но это не полная нет-нет. Если у вас есть побочные эффекты, это делает затруднительным / невозможным работу вызывающих абонентов чисто функциональным способом. Это может или не может быть проблемой в зависимости от вашего варианта использования.

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

1 голос
/ 14 февраля 2012

Еще одна проблема заключается в том, что метод может быть «неправильно использован» в том смысле, что вызывающий может попытаться использовать его для перемещения файлов, не проявляя интереса к полученным результатам.

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

Проблема обсуждается в этом посте: http://codequota.com/archive/2012/02/13/iterator-blocks-and-side-effects.aspx

1 голос
/ 26 ноября 2008

Итераторы, которые являются логически перечислениями над коллекциями, не должны иметь побочных эффектов, нет. В частности, они не будут идемпотентными при перезапуске с помощью метода IEnumerator.Reset ().

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

0 голосов
/ 26 ноября 2008

Я не буду комментировать общий случай, но в вашем случае я думаю, что это опасно . Хорошим показателем качества интерфейса является то, насколько легко использовать интерфейс и насколько сложно его использовать.

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

На самом деле я бы пошел дальше, чем Джон, и сказал бы: даже не предлагайте такой вариант. Это может быть полезно, но цена потенциального использования этого неправильного может быть слишком высокой. С другой стороны, можно утверждать, что если пользователь намеренно делает выбор, ему (ей) приходится иметь дело с последствиями.

0 голосов
/ 26 ноября 2008

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

0 голосов
/ 26 ноября 2008

Я бы сказал, что побочные эффекты - плохая идея, но не вредная. Если у вас есть побочные эффекты, вы делаете две операции. Лучше разделить эти операции на две функции, чтобы облегчить поддержку кода, и вы могли бы выполнять их отдельно.

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

0 голосов
/ 26 ноября 2008

Спасибо, ребята - и блаженный! быстрые ответы!

Я должен согласиться, что побочные эффекты в итераторе - плохая идея. Тот факт, что я должен был спросить, указывает на запах. Должен был выслушать мое чувство пауков.

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

Кроме того, я думаю, что я связал идею посетителя с итератором, что тоже не очень хорошая идея.

С тех пор я изменил свою реализацию, чтобы получить 2 последовательности из моей исходной последовательности всех файлов - один хороший, другой плохой. Теперь я могу обработать их более наглядно и интуитивно. Hooray.

Итак, я до сих пор не использовал итератор в реальном мире. Ну хорошо.

Спасибо! Matt

0 голосов
/ 26 ноября 2008

Мое эмпирическое правило: если я перебираю коллекцию, нет. Но в Python цикл for часто используется идиоматически для выполнения кода определенное количество раз, и в этом случае у меня нет проблем с использованием его с побочными эффектами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...