Дело в том, что «неправильно» в том, что goto
может реализовывать многие виды механизмов управления, а не только throw
, и поэтому имеет небольшую внутреннюю структуру.Из-за этого есть несколько причин, по которым программисту было бы интересно использовать альтернативы goto
:
Во-первых, мы начинаем видеть переход скриптов из чисто интерпретируемого в скомпилированный байт-код.Хорошие примеры этого можно найти где угодно, например, Python, Perl 6, Scala (Lift), Clojure (Compojure).Даже в PHP есть компиляторы байт-кода.Поскольку goto
имеет небольшую структуру, компиляция механизмов управления не может произойти, что является значительной потерей производительности, потому что современные компиляторы, как правило, очень хороши в этом.Для throw
компиляторы могут начать предполагать, что генерируемое исключение не является распространенным, и, следовательно, оно оптимизирует «нормальный» путь управления часто за счет менее оптимального «ненормального» пути управления.
Дажеесли у вас нет полноценного компилятора, интерпретаторы могут значительно помочь программисту, когда программист использует механизмы управления, которые имеют большую структуру.Например, блоки циклов for
лексически ограничены компилятором / интерпретатором, и поэтому программист может использовать эту область видимости для модуляции кусков кода.Иначе, с goto
вы вынуждены загрязнять пространство имен переменной.
Кроме того, если ваш язык позволяет вам объявлять методы, которые throw
исключают, компилятор / интерпретатор может сообщить вам, что вы не обработали все возможные исключения, с которыми могут сталкиваться вызываемые вами методы (аналогичноthrows
Java, если у вас есть опыт там).С goto
компилятор не знает, что вы пытаетесь сделать, поэтому он не поможет вам во время компиляции и тестирования.
Goto также требует от программиста восстановления после ошибки.Представьте, что у вас есть такой код (вырванный и отредактированный из ваших фрагментов):
if (!isset($a)) {
$message = '$a is not set';
goto errorA;
}
if (!isset($b)) {
$message = '$b is not set';
goto errorB;
}
if (!moonInRightPhase) {
goto errorP
}
echo '$a + $b = '.($a + $b)."<br>\n";
errorA:
// Do something non-trivial and unique to handle $a not being set.
goto afterError
errorP:
// Do something non-trivial and unique to handle moon phase
// This error requires drastic failure of code path:
goto failure
errorB:
// Do something non-trivial and unique to handle $b not being set.
goto afterError
afterError:
// Program continues
return SUCCESS
failure:
return FAILURE
Проблема здесь в том, что программист обязан поступать правильно.Если он забудет goto afterError
, он пройдет по следующему пути исключения.С throw
механизмы менее подвержены ошибкам.
Наконец, мой личный опыт заставляет меня не любить выражение goto
просто потому, что его нелегко читать.Когда я пытаюсь понять фрагмент кода с четырьмя или пятью метками с именами some-error
, fail
, retry
, и они не расположены рядом с кодом, нарушающим / исключающим, это может стать кошмаром для распутывания,И если его нелегко прочитать, то даже программист, пытающийся пересмотреть то, что он или она сделал год назад, может привести к ошибкам.
Как постскриптум к этому ответу, я не верю "неправильно""это правильный способ описать goto
.Это могло произойти из сенсации знаменитой газеты Дейкстры.«Мощный» может быть лучшим термином, поскольку он подразумевает, что он может делать практически все, но даже самые простые ошибки делают «неправильное» превращением в «ужасно неправильное».Мы не должны запрещать инструменты, потому что они действительно опасны;мы должны лучше информировать людей об их опасности и позволить им решать.