Мой босс продолжает упоминать беспечно , что плохие программисты используют break
и continue
в петлях.
Я использую их все время, потому что они имеют смысл; позвольте мне показать вам вдохновение:
function verify(object) {
if (object->value < 0) return false;
if (object->value > object->max_value) return false;
if (object->name == "") return false;
...
}
Дело в том, что сначала функция проверяет правильность условий, а затем выполняет фактическую функциональность. ИМО же относится и к петлям:
while (primary_condition) {
if (loop_count > 1000) break;
if (time_exect > 3600) break;
if (this->data == "undefined") continue;
if (this->skip == true) continue;
...
}
Я думаю, что это облегчает чтение и отладку; но я также не вижу обратной стороны.
goto
) полезны в некоторых случаях.Ответы:
При использовании в начале блока, когда выполняются первые проверки, они действуют как предварительные условия, так что это хорошо.
При использовании в середине блока с некоторым кодом они действуют как скрытые ловушки, так что это плохо.
источник
Вы можете прочитать статью Дональда Кнута « Структурированное программирование » 1974 года , в которой можно перейти к «Утверждениям» , в которой он обсуждает различные варианты использования,
go to
которые являются структурно желательными. Они включают эквивалентbreak
иcontinue
операторы (многие из примененийgo to
в них были разработаны в более ограниченные конструкции). Ваш начальник - тип, который называет Кнута плохим программистом?(Примеры приведены меня интересуют. Как правило,
break
иcontinue
не любят людей , которые любят один вход и один выход из любой части кода, и что такой человек также хмурится на несколькоreturn
утверждений.)источник
Break
,Continue
иExit
как инструменты в моем наборе инструментов; Я использую их там, где это облегчает понимание кода, и не использую их там, где это усложнит чтение.Я не верю, что они плохие. Идея, что они плохие, пришла со времен структурированного программирования. Это связано с тем, что функция должна иметь одну точку входа и одну точку выхода, то есть только одну
return
на функцию.Это имеет некоторый смысл, если ваша функция длинная, и если у вас есть несколько вложенных циклов. Однако ваши функции должны быть короткими, и вы должны обернуть петли и их тела в свои собственные короткие функции. Как правило, принуждение функции иметь единую точку выхода может привести к очень запутанной логике.
Если ваша функция очень короткая, если у вас один цикл или, в худшем случае, два вложенных цикла, и если тело цикла очень короткое, тогда очень ясно, что делает a
break
или acontinue
. Также ясно, чтоreturn
делают несколько утверждений.Эти проблемы рассматриваются в «Чистом коде» Роберта К. Мартина и в «Рефакторинге» Мартина Фаулера.
источник
CALL P(X, Y, &10)
, и в случае ошибки функция может передать управление этому оператору вместо возврата к точке вызова.Плохие программисты говорят в абсолютах (как Ситх). Хорошие программисты используют самое ясное из возможных решений (при прочих равных условиях ).
Использование break и continue часто затрудняет отслеживание кода. Но если их замена делает код еще сложнее для понимания, это плохое изменение.
Пример, который вы привели, определенно представляет собой ситуацию, в которой разрывы и продолжения должны быть заменены чем-то более элегантным.
источник
Большинство людей думают, что это плохая идея, потому что поведение не легко предсказуемо. Если вы читаете код и видите
while(x < 1000){}
, что он будет работать до тех пор, пока x> = 1000 ... Но если в середине есть перерывы, то это не так, поэтому вы не можете доверять своему зацикливание ...Это та же самая причина, по которой людям не нравится GOTO: конечно, это может быть хорошо использовано, но это также может привести к ужасному коду спагетти, где код случайным образом переходит от раздела к разделу.
Для себя, если бы я собирался сделать цикл, который нарушал более чем одно условие, я бы
while(x){}
тогда переключил X на false, когда мне нужно было выйти. Окончательный результат будет таким же, и любой, кто читает код, будет знать, что нужно присмотреться к вещам, которые изменили значение X.источник
while(notDone){ }
подхода.break;
наx=false;
не делает ваш код более понятным. Вы все еще должны искать тело для этого утверждения. И в случае,x=false;
если вам нужно будет убедиться, что это не ударитx=true;
дальше.while (x < 1000)
я предполагаю, что это будет работать 1000 раз». Ну, есть много причин, почему это неверно, даже еслиx
изначально он равен нулю. Например, кто говорит, чтоx
во время цикла увеличивается только один раз, и никогда не изменяется каким-либо другим способом? Даже по вашему собственному предположению, просто потому, что что-то установленоx >= 1000
, не означает, что цикл закончится - он может быть установлен обратно в диапазон, прежде чем условие будет проверено.Да, вы можете [пере] писать программы без операторов прерывания (или возврата из середины циклов, которые делают то же самое). Но вам, возможно, придется ввести дополнительные переменные и / или дублирование кода, которые обычно затрудняют понимание программы. По этой причине Pascal (язык программирования) был очень плох, особенно для начинающих программистов. Ваш начальник в основном хочет, чтобы вы программировали в управляющих структурах Паскаля. Если бы Линус Торвальдс был на вашем месте, он, вероятно, показал бы вашему боссу средний палец!
Есть результат компьютерной науки, который называется иерархия структур управления Косараджу, которая восходит к 1973 году и упоминается в (более) известной статье Кнута о gotos от 1974 года. (Кстати, эта статья Кнута была уже рекомендована Дэвидом Торнли выше) .) То, что С. Рао Косараю доказал в 1973 году, заключается в том, что невозможно переписать все программы, имеющие многоуровневые разрывы глубины n, в программы с глубиной разрывов меньше, чем n, без введения дополнительных переменных. Но допустим, что это чисто теоретический результат. (Просто добавьте несколько дополнительных переменных ?! Конечно, вы можете сделать это, чтобы угодить своему боссу ...)
Что гораздо важнее с точки зрения разработки программного обеспечения, это более поздняя статья Эрика С. Робертса 1995 года под названием « Выход из цикла и структурированное программирование: возобновление дебатов» ( http://cs.stanford.edu/people/eroberts/papers/SIGCSE- 1995 / LoopExits.pdf ). Робертс суммирует несколько эмпирических исследований, проведенных другими до него. Например, когда группу студентов типа CS101 попросили написать код для функции, реализующей последовательный поиск в массиве, автор исследования сказал следующее о тех студентах, которые использовали break / return / goto для выхода из последовательный цикл поиска, когда элемент был найден:
Робертс также говорит, что:
Да, вы можете быть более опытным, чем учащиеся CS101, но без использования оператора break (или эквивалентного возврата / перехода из середины цикла), в конце концов вы напишите код, который, хотя номинально хорошо структурирован, достаточно сложен с точки зрения дополнительной логики Переменные и дублирование кода, что кто-то, вероятно, вы сами, добавите в него логические ошибки, пытаясь следовать стилю кодирования вашего босса.
Я также хочу сказать, что статья Робертса гораздо более доступна для среднего программиста, поэтому лучше читать ее сначала, чем книгу Кнута. Это также короче и охватывает более узкую тему. Вы могли бы даже рекомендовать это своему боссу, даже если он является менеджером, а не типом CS.
источник
Я не рассматриваю возможность использования какой-либо из этих плохих практик, но слишком частое их использование в одном и том же цикле должно оправдать переосмысление логики, используемой в цикле. Используйте их экономно.
источник
Приведенный вами пример не нуждается ни в перерывах, ни в продолжении:
Моя «проблема» с четырьмя строками в вашем примере заключается в том, что все они находятся на одном уровне, но они делают разные вещи: некоторые ломаются, некоторые продолжают ... Вы должны прочитать каждую строку.
В моем вложенном подходе, чем глубже вы идете, тем более «полезным» становится код.
Но если в глубине души вы найдете причину для остановки цикла (кроме первичного условия), то для его использования понадобится разрыв или возврат. Я бы предпочел это использованию дополнительного флага, который должен быть проверен в состоянии верхнего уровня. Перерыв / возврат более прямой; это лучше заявляет намерение чем установка еще одной переменной.
источник
<
сравнения должны<=
соответствовать решению ОП«Плохость» зависит от того, как вы их используете. Обычно я использую разрывы в конструкциях циклов ТОЛЬКО тогда, когда это спасет меня от циклов, которые невозможно сохранить с помощью рефакторинга алгоритма. Например, циклически просматривая коллекцию в поисках элемента со значением в определенном свойстве, установленном в значение true. Если все, что вам нужно знать, это то, что для одного из элементов это свойство установлено в значение true, как только вы достигнете этого результата, разрыв подходит для правильного завершения цикла.
Если использование разрыва не сделает код более простым для чтения, более коротким для выполнения или существенным образом сохраненным циклами обработки, то лучше их не использовать. Я стараюсь кодировать «наименьший общий знаменатель», когда это возможно, чтобы каждый, кто следует за мной, мог легко посмотреть на мой код и выяснить, что происходит (я не всегда успешен в этом). Перерывы уменьшают это, потому что они вводят нечетные точки входа / выхода. При неправильном использовании они могут вести себя очень как неуместное утверждение «goto».
источник
Абсолютно нет ... Да, использование
goto
плохо, потому что это ухудшает структуру вашей программы, а также очень трудно понять поток управления.Но использование таких утверждений, как
break
иcontinue
является абсолютно необходимым в наши дни, и вовсе не считается плохой практикой программирования.А также не так сложно понять поток управления в использовании
break
иcontinue
. В конструкциях , какswitch
вbreak
заявлении абсолютно необходимо.источник
Основным понятием является возможность семантического анализа вашей программы. Если у вас есть один вход и один выход, математика, необходимая для обозначения возможных состояний, значительно проще, чем если бы вам приходилось управлять путями разветвления.
Частично эта трудность отражается в способности концептуально рассуждать о вашем коде.
Честно говоря, ваш второй код не очевиден. Что это делает? Продолжить «продолжить» или «следующий» цикл? Понятия не имею. По крайней мере, ваш первый пример понятен.
источник
Я бы заменил ваш второй фрагмент кода на
не по каким-то причинам краткости - я на самом деле думаю, что это легче читать, а кому-то понять, что происходит. Вообще говоря, условия для ваших петель должны содержаться исключительно в тех условиях петли, которые не засорены по всему телу. Однако есть некоторые ситуации, где
break
иcontinue
может помочь читабельность.break
больше, чемcontinue
я мог бы добавить: Dисточник
foreach
циклу, так как он будет просто повторять каждый элемент в коллекции.for
Цикл аналогичен тем , что он не должен иметь условную конечную точку. Если вам нужна условная конечная точка, вам нужно использоватьwhile
цикл.break
на мой взгляд, из цикла должен быть только один максимум.Я не согласен с вашим боссом. Есть соответствующие места для
break
иcontinue
будет использоваться. Фактически причина того, что исключения и обработка исключений были введены в современные языки программирования, заключается в том, что вы не можете решить все проблемы, используя толькоstructured techniques
.В дополнение к этому я не хочу начинать религиозную дискуссию здесь, но вы могли бы реструктурировать свой код так, чтобы он был еще более читабельным:
На другой стороне заметки
Мне лично не нравится использование
( flag == true )
в условных выражениях, потому что если переменная уже является логической, то вы вводите дополнительное сравнение, которое должно произойти, когда значение логической переменной имеет нужный вам ответ - если, конечно, вы не уверены, что ваш компилятор будет оптимизировать это дополнительное сравнение прочь.источник
boolean
есть или что означает лаконичная / изящная терминология, тогда, возможно, вам лучше нанять более умных сопровождающих ;-)Я согласен с вашим боссом. Они плохие, потому что они производят методы с высокой цикломатической сложностью. Такие методы трудны для чтения и тестирования. К счастью, есть простое решение. Извлеките тело цикла в отдельный метод, где «continue» становится «return». «Возвращение» лучше, потому что после «возвращения» все кончено - нет беспокойства о местном штате.
Для «break» извлеките сам цикл в отдельный метод, заменив «break» на «return».
Если извлеченные методы требуют большого количества аргументов, это указание для извлечения класса - либо соберите их в объект контекста.
источник
Я думаю, что это проблема только тогда, когда она вложена глубоко в несколько циклов. Трудно понять, на какую петлю вы выходите. Может быть также трудно следовать продолжению, но я думаю, что настоящая боль исходит от перерывов - может быть трудно следовать логике.
источник
break 2
; для других, я думаю, используются временные флаги boolПока они не используются как замаскированное goto, как в следующем примере:
Я в порядке с ними. (Пример видно из производственного кода, ме)
источник
Мне не нравится ни один из этих стилей. Вот что я бы предпочел:
Я действительно не люблю использовать,
return
чтобы прервать функцию. Это похоже на злоупотреблениеreturn
.Использование
break
также не всегда понятно для чтения.Еще лучше может быть:
меньше вложенности, а сложные условия преобразуются в переменные (в реальной программе вам нужно иметь более подходящие имена, очевидно ...)
(Весь приведенный выше код является псевдокодом)
источник
break
иcontinue
. Неправильное окончание цикла просто кажется странным, и мне это не нравится.continue
означает пропустить функциональность и перейти к следующему циклу; не "продолжить выполнение"Нет. Это способ решить проблему, и есть другие способы ее решения.
Многие текущие основные языки (Java, .NET (C # + VB), PHP, напишите свой собственный) используют «break» и «continue» для пропуска циклов. Они оба "структурированные предложения goto (s)".
Без них:
С ними:
Обратите внимание, что код «break» и «continue» короче и обычно превращает «while» в предложения «for» или «foreach».
Оба случая являются вопросом стиля кодирования. Я предпочитаю не использовать их , потому что многословный стиль позволяет мне лучше контролировать код.
Я на самом деле работаю в некоторых проектах, где было обязательно использовать эти предложения.
Некоторые разработчики могут подумать, что они не являются необходимыми, но гипотетическими, если мы должны были удалить их, мы должны также удалить «while» и «do while» («повторить до», вы, ребята, паскали);
Заключение, даже если я предпочитаю не использовать их, я думаю , что это вариант, а не плохая практика программирования.
источник
Я не против
continue
иbreak
в принципе, но я думаю, что это очень низкоуровневые конструкции, которые очень часто можно заменить чем-то еще лучше.Я использую C # в качестве примера, рассмотрим случай итерации по коллекции, но нам нужны только элементы, которые удовлетворяют некоторому предикату, и мы не хотим делать больше, чем максимум 100 итераций.
Это выглядит достаточно разумно чистым. Это не очень сложно понять. Я думаю, что выиграло бы от большей декларации. Сравните это со следующим:
Возможно, вызовы Where и Take даже не должны быть в этом методе. Возможно, эту фильтрацию следует выполнить ДО того, как коллекция будет передана этому методу. В любом случае, отойдя от низкоуровневых вещей и сконцентрировавшись больше на реальной бизнес-логике, становится все более ясным, чем мы на самом деле интересуемся. Становится легче разделить наш код на связные модули, которые в большей степени придерживаются хороших методов проектирования и т. на.
Низкоуровневые вещи все еще будут существовать в некоторых частях кода, но мы хотим скрыть это как можно больше, потому что это требует умственной энергии, которую мы могли бы использовать вместо того, чтобы рассуждать о проблемах бизнеса.
источник
В Code Complete есть хороший раздел об использовании
goto
и многократных возвратах из процедуры или цикла.В целом это неплохая практика.
break
илиcontinue
скажи точно, что будет дальше. И я с этим согласен.Стив Макконнелл (автор Code Complete) использует почти те же примеры, что и вы, чтобы показать преимущества использования различных
goto
операторов.Однако злоупотребление
break
илиcontinue
может привести к сложному и не поддерживаемому программному обеспечению.источник