Goto
Нередко в разговорах программистов всплывает тема оператора «goto». Например, сообщество крупно побурлило после появления его в ПХП. Многие считают, что оператор вредный, его появление в языке «понижает» язык в классе до Бейсика (хотя современные Бейсики — очень мощные языки) и он несёт только вред.
Грустно то, что обычно критики предоставляют аргументы на уровне вкусовщины, даже не пытаясь сформулировать аргументы, видимо считая, что уровень «плохо, потому что goto» достаточен.
Попробую возразить.
Во-первых, если считать, что присутствие упомянутого оператора ставит язык в один ряд с худшими Бейсиками, то туда же низбежно попадают Ассемблеры и Си — языки, программировать на которых никогда зазорно не было (в Ассемблере goto называется иначе, но суть абсолютно та же).
Во-вторых, во многих языках goto уже есть. Только у него разные названия для разных целей, обычно это break и continue. Они всегда были в ПХП, есть они и в Перле, ПХП, Пайтоне, Джаве и многих других языках.
С последним аргументам в спорах обычно не соглашаются, говорят, что goto как правило умеет больше, чем эта пара операторов. Тут надо отступить и вспомнить чем вообще был плох обсуждаемый оператор.
Плох он, вообще говоря, одной-единственной вещью: бесконтрольным переходом куда бы то ни было. Вредными признаны переходы внутрь функций и процедур, внутрь циклов, управляющих конструкций, переход без возврата в вызывающий код и тому подобными вещами. Эти переходы очень запутывают логику приложений и легко приводят к появлению ошибок.
Так вот, всего этого современный оператор просто не умеет. Современный goto — тёзка того старого, плохого, сейчас он умеет переходить на метку, но не на всякую, а с огромным количеством ограничений и его использование не более вредно или стыдно, чем использование break или continue.
Да нормальный оператор, но я так ни разу им и не воспользовался -- ни разу не понадобился настолько чтобы им пользоваться без ухудшения читаемости.
Так правильно, break и continue — это частные случаи goto; break и continue — это очень плохо, и нужно стараться их никогда-никогда не использовать.
Комментарий для besisland.name:
Это утверждение лучше бы смотрелось в паре с аргументом.
Комментарий для besisland.name:
Что может привести к ещё большей запутанности кода, чем даже с goto.
Упс… понял, что могу быть понят двусмысленно — неиспользование break и continue может привести к ещё более нечитаемому коду, чем даже использование goto.
Денис Попов идеально подходит на роль аналитика, поведение которого описал Евгений.
«Это плохо, ужасно плохо», а что именно плохо -- загадка.
Ничего плохого в гото нет. Да, его использование может усложнить код.
Но в редких ситуациях именно он может секономить много времени и кода.
А ещё try-catch-throw — это вообще ужосѣ
ну ок.
goto — это jump в чистом виде.
break/continue — это первая производная от goto, jump с кучей проверок.
try/catch/throw/finally — опять всё то же самое goto, только уже с объектным душком и всякими рюшечками. но всё равно всё сводится к банальному jump.
да ведь, в конце концов, return это оно же самое. возврат на стек, регистры восстановить, а потом — jump. но только почему никто не говорит, что return это плохо, и его надо выпилить? чё народ так непоследовательно-то мыслит?
Я что-то не могу представить себе программу, использующую goto, которая от его использования стала проще, и не являлась бы спагетти-кодом. Это в любом случае будут бесконтрольные переходы, запутывающие логику и вызывающие ошибки.
break и continue — скорее не goto с кучей проверок, а оператор, работающий единственно возможным способом. И их можно рассматривать не как goto, а как синтаксический сахар для if/else с дополнительными переменными.
Комментарий для fulc.ru:
break и continue, к сожалению, работают только в циклах. Иногда надо сделать break из обычного if и цикла сверху нет.
Комментарий для besisland.name:
Кстати, напишите мне поиск указанного элемента массива без break.
Вместо continue — просто оборачиваем в if.
Вместо break — добавляем условие цикла:
http://pastebin.com/ZM75jLzK
Я ещё return забыл — это тоже разновидность goto.
А вот try…catch — это goto технически, но не по смыслу. Их смысл — не в переходе в другое место программы, а в аварийной передаче управления.
Комментарий для besisland.name:
Т. е. цикл каждую итерацию теперь проверяет ещё одно, совершенно ненужное условие? Плохое решение. Но, вы, смотрю, не специалист в программировании. is_null (функция) вместо === null (конструкция), count, вычисляемый в каждую итерацию цикла.
В общем, у вас простительные заблуждения.
Комментарий для Евгения Степанищева:
зачем так? некрасиво же. то что в тестовом примере у человека count вычисляется каждую итерацию, не делает его автоматически неправым во всех остальных утверждениях. правым впрочем тоже.
Комментарий для zg.livejournal.com:
Да, пожалуй. Денис, прошу прощения.
Комментарий для Евгения Степанищева:
А с использованием break он не будет проверять его каждый раз перед break? Можно в цикле просто получать элемент в переменную, а в условии проверять, она это или нет, будет по одной проверке на цикл.
Ну и, в любом случае, эта break тут помогает код организовать, избавление от лишнего вызова асимптотически ни на что не влияет, да и, скорее всего, будет преждевременной оптимизацией.
Комментарий для fulc.ru:
Да, тут я промахнулся.
Не путай качество кода и преждевременную оптимизацию. То, что оптимизация не должна быть преждевременной не говорит о том, что код надо писать плохо.
Добрый день.
Работал пару лет назад в компании, в которой очень сильно следили за качеством кода, поэтому были огромные своды правил, как с точки зрения аккуратности кода (4 пробела вместо табов, отсутствие лишних пробелов в инструкциях или наличие таковых для удобочитаемости, и т. д.), так и с технической точки зрения (не использовать goto, continue, break, и т. д.).
Однако, всё время в компании ходят споры о том, почему это нельзя делать: никто доводов толковых не приводил. Я сам об этом читал в книгах, вроде МакКоннел «Совершенный код», и т. д.
Везде один довод: «запутанность кода». Однако при правильном разбиении кода на методы и нормальной архитектуре, по-моему, break и continue приводит только к большей понятности кода.
И вот, читая интереснейший цикл статей «Что каждый программист должен знать о памяти» я нарвался на доступное объяснение чем плох любой переход (JUMP) с точки зрения производительности (ссыль http://rus-linux.net/lib.php?name=/MyLDP/hard/memory/memory-6-3.html%29:
« Код имеет то преимущество, что между переходами он линеен. В такие периоды процессор может эффективно делать предварительную загрузку памяти. Переходы нарушают эту идеальную картину из-за того что
Эти проблемы создают задержки при выполнении кода с возможным существенным снижением производительности.»
Комментарий для http://gdriv.es/optiklab:
В случае интерпретируемых языков аргумент не принимается. Потому что при интерпретации происходит целая куча переходов, которые вы не видите. Кстати говоря, вызов любой функции/процедуры/метода — такой же переход.