Что такого плохого в goto, когда оно используется для этих очевидных и актуальных случаев?

40

Я всегда знал, что gotoэто что-то плохое, запертое в подвале где-то, что никогда нельзя увидеть навсегда, но сегодня я наткнулся на пример кода, который имеет смысл использовать goto.

У меня есть IP-адрес, где мне нужно проверить, есть ли в списке IP-адресов, а затем продолжить с кодом, в противном случае выдается исключение.

<?php

$ip = '192.168.1.5';
$ips = [
    '192.168.1.3',
    '192.168.1.4',
    '192.168.1.5',
];

foreach ($ips as $i) {
    if ($ip === $i) {
        goto allowed;
    }
}

throw new Exception('Not allowed');

allowed:

...

Если я не использую, gotoто я должен использовать некоторые переменные, такие как

$allowed = false;

foreach ($ips as $i) {
    if ($ip === $i) {
        $allowed = true;
        break;
    }
}

if (!$allowed) {
    throw new Exception('Not allowed');
}

Мой вопрос в том, что такого плохого в том, gotoкогда он используется для таких очевидных и не соответствующих им дел?

php_nub_qq
источник
Комментарии не для расширенного обсуждения; этот разговор был перемещен в чат .
maple_shaft

Ответы:

120

Само GOTO - это не непосредственная проблема, это неявные конечные автоматы, которые люди, как правило, используют с его помощью. В вашем случае вам нужен код, который проверяет, есть ли IP-адрес в списке разрешенных адресов, следовательно,

if (!contains($ips, $ip)) throw new Exception('Not allowed');

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

Но если вы поместите код, который выполняет проверку, в вашу основную программу, вы потеряете это. Вы вводите изменяемое состояние либо явно:

$list_contains_ip = undef;        # STATE: we don't know yet

foreach ($ips as $i) {
  if ($ip === $i) {
      $list_contains_ip = true;   # STATE: positive
      break;
  }
                                  # STATE: we still don't know yet, huh?                                                          
                                  # Well, then...
  $list_contains_ip = false;      # STATE: negative
}

if (!$list_contains_ip) {
  throw new Exception('Not allowed');
}

где $list_contains_ipваша единственная переменная состояния или неявно:

                             # STATE: unknown
foreach ($ips as $i) {       # What are we checking here anyway?
  if ($ip === $i) {
    goto allowed;            # STATE: positive
  }
                             # STATE: unknown
}
                             # guess this means STATE: negative
throw new Exception('Not allowed');

allowed:                     # Guess we jumped over the trap door

Как видите, в конструкции GOTO есть необъявленная переменная состояния. Само по себе это не проблема, но эти переменные состояния похожи на камешки: нести с собой не сложно, но с сумкой, полной их, вы потеете. Ваш код не останется прежним: в следующем месяце вас попросят разграничить частные и публичные адреса. Через месяц ваш код должен будет поддерживать диапазоны IP-адресов. В следующем году кто-то попросит вас поддержать адреса IPv6. Вскоре ваш код будет выглядеть так:

if ($ip =~ /:/) goto IP_V6;
if ($ip =~ /\//) goto IP_RANGE;
if ($ip =~ /^10\./) goto IP_IS_PRIVATE;

foreach ($ips as $i) { ... }

IP_IS_PRIVATE:
   foreach ($ip_priv as $i) { ... }

IP_V6:
   foreach ($ipv6 as $i) { ... }

IP_RANGE:
   # i don't even want to know how you'd implement that

ALLOWED:
   # Wait, is this code even correct?
   # There seems to be a bug in here.

И тот, кто должен отладить этот код, проклянет вас и ваших детей.

Дейкстра формулирует это так:

Необузданное использование оператора go to приводит к немедленному следствию о том, что становится чрезвычайно трудно найти значимый набор координат, в которых можно описать ход процесса.

И именно поэтому GOTO считается вредным.

Валленборн
источник
22
Это $list_contains_ip = false;утверждение кажется неуместным
Берги
1
Сумка с галькой легка, у меня есть удобная сумка для их хранения. : p
whatsisname
13
@ Берги: Ты прав. Это показывает, как легко все испортить.
Валленборн
6
@whatsisname Эта сумка называется функцией / классом / пакетом для их хранения. использовать gotos - все равно, что жонглировать ими и выбрасывать сумку.
Falco
5
Мне нравится цитата из Дейкстры, я не слышал, чтобы это выразилось так, но это действительно хорошая мысль. Вместо того, чтобы иметь поток, который в значительной степени сверху вниз, внезапно у вас есть что-то, что может прыгать по всей странице в произвольном порядке. Говоря кратко, это довольно впечатляет.
Билл К
41

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

if (!in_array($ip, $ips)) throw new Exception('Not allowed');

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

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

JacquesB
источник
5
@jameslarge Хотите it's easier to write good optimizing compilers for "structured" languages.разработать? В качестве встречного примера люди из Rust представили MIR - промежуточное представление в компиляторе, которое специально заменяет циклы, продолжения, разрывы и т. Д. На gotos, потому что его проще проверять и оптимизировать.
8bittree
6
«если у вас нет другого выбора, вы используете GOTO» Это было бы чрезвычайно редко. Я, честно говоря, не могу вспомнить случай, когда у вас нет другого выбора, кроме совершенно нелепых ограничений, препятствующих рефакторингу существующего кода или подобной чепухе.
jpmc26
8
Кроме того, IMO, эмулирующее a gotoс использованием крысиных флагов и условных выражений (как во втором примере OP), гораздо менее читабельно, чем просто использование a goto.
3
@ 8bittree: структурированное программирование предназначено для исходного языка, а не для целевого языка компилятора. Целевым языком для нативных компиляторов являются инструкции процессора, которые явно не «структурированы» в смысле языка программирования.
Роберт Харви
4
@ 8bittree Ответ на ваш вопрос о MIR находится в предоставленной вами ссылке: «Но хорошо иметь такую ​​конструкцию в MIR, потому что мы знаем, что она будет использоваться только определенными способами, например, для выражения цикла или разрыва». «. Другими словами, поскольку goto не разрешен в Rust, они знают, что он структурирован, и промежуточная версия с gotos тоже. В конечном итоге, код должен перейти в режим машинных команд. Что я понял по вашей ссылке, так это то, что они просто добавляют пошаговый шаг в переводе с языка высокого уровня на язык низкого уровня.
JimmyJames
17

Как уже говорили другие, проблема не в gotoсамом себе; проблема в том, как люди используют goto, и как это может усложнить понимание и поддержку кода.

Предположим следующий фрагмент кода:

       i = 4;
label: printf( "%d\n", i );

Какое значение печатается для i? Когда это напечатано? Пока вы не учтете каждый экземпляр goto labelвашей функции, вы не сможете знать. Простое присутствие этой метки разрушает вашу способность отлаживать код простым осмотром. Для небольших функций с одной или двумя ветвями проблем не так много. Для немалых функций ...

Еще в начале 90-х нам дали кучу кода C, который работал на трехмерном графическом дисплее и сказал, чтобы он работал быстрее. Это было всего около 5000 строк кода, но все это было в main, и автор использовал около 15 или около того gotoразветвления в обоих направлениях. С самого начала это был плохой код, но его присутствие gotoсделало его намного хуже. Моему коллеге понадобилось около 2 недель, чтобы разобраться с потоком контроля. Более того, это gotoпривело к тому, что код был так тесно связан с самим собой, что мы не смогли внести никаких изменений, не нарушив что-либо.

Мы попытались скомпилировать с оптимизацией уровня 1, и компилятор съел всю доступную оперативную память, затем всю доступную подкачку, а затем запаниковал систему (что, вероятно, не имело ничего общего с gotoсамими s, но мне нравится выкидывать этот анекдот).

В итоге мы предоставили заказчику два варианта - давайте переписать все с нуля или купим более быстрое оборудование.

Они купили более быстрое оборудование.

Правила Боде по использованию goto:

  1. Только ветвь вперед;
  2. Не обходите управляющие структуры (т. Е. Не переходите в тело оператора ifor forили or while);
  3. Не используйте gotoвместо контрольной структуры

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

РЕДАКТИРОВАТЬ

Расширяя это последнее утверждение, вот один из немногих допустимых вариантов использования для goto. Предположим, у нас есть следующая функция:

T ***myalloc( size_t N, size_t M, size_t P )
{
  size_t i, j, k;

  T ***arr = malloc( sizeof *arr * N );
  for ( i = 0; i < N; i ++ )
  {
    arr[i] = malloc( sizeof *arr[i] * M );
    for ( j = 0; j < M; j++ )
    {
      arr[i][j] = malloc( sizeof *arr[i][j] * P );
      for ( k = 0; k < P; k++ )
        arr[i][j][k] = initial_value();
    }
  }
  return arr;
}

Теперь у нас есть проблема - что делать, если один из mallocвызовов не проходит в середине? В отличие от этого события, мы не хотим возвращать частично выделенный массив и не хотим просто выйти из функции с ошибкой; мы хотим очистить себя и освободить частично выделенную память. В языке, который выдает исключение при неправильном выделении ресурсов, это довольно просто - вы просто пишете обработчик исключений, чтобы освободить то, что уже было выделено.

В C вы не имеете структурированной обработки исключений; Вы должны проверить возвращаемое значение каждого mallocзвонка и принять соответствующие меры.

T ***myalloc( size_t N, size_t M, size_t P )
{
  size_t i, j, k;

  T ***arr = malloc( sizeof *arr * N );
  if ( arr )
  {
    for ( i = 0; i < N; i ++ )
    {
      if ( !(arr[i] = malloc( sizeof *arr[i] * M )) )
        goto cleanup_1;

      for ( j = 0; j < M; j++ )
      {
        if ( !(arr[i][j] = malloc( sizeof *arr[i][j] * P )) )
          goto cleanup_2;

        for ( k = 0; k < P; k++ )
          arr[i][j][k] = initial_value();
      }
    }
  }
  goto done;

  cleanup_2:
    // We failed while allocating arr[i][j]; clean up the previously allocated arr[i][j]
    while ( j-- )
      free( arr[i][j] );
    free( arr[i] );
    // fall through

  cleanup_1:
    // We failed while allocating arr[i]; free up all previously allocated arr[i][j]
    while ( i-- )
    {
      for ( j = 0; j < M; j++ )
        free( arr[i][j] );
      free( arr[i] );
    }

    free( arr );
    arr = NULL;

  done:
    return arr;
}

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

Джон Боде
источник
Мне нравятся эти правила. Я бы по-прежнему не использовал gotoдаже в соответствии с этими правилами - я бы не использовал его вообще, если только это не единственная форма ветвления, доступная на языке, - но я вижу, что отладка не будет слишком большим кошмаром gotoЭто если они были написаны в соответствии с этими правилами.
Подстановочный
если вам нужно выйти из глубоко вложенного цикла, вам просто нужно сделать этот цикл другой функцией и вернуть
bunyaCloven
6
Как-то однажды кто-то резюмировал это для меня: «Это не проблема, а проблема, возникшая в результате». Как специалист по оптимизации программного обеспечения, я согласен, что неструктурированный поток управления может создать компиляторы (и люди!) Для цикла. Однажды я потратил часы на расшифровку простого конечного автомата (четыре из пяти состояний) в функции BLAS, в которой использовались различные формы GOTO, в том числе известные фортрановские (in) известные арифметические переходы, если я правильно помню.
njuffa
@njuffa "Как специалист по оптимизации программного обеспечения, я согласен, что неструктурированный поток управления может бросить компиляторы (и людей!) в цикл." - есть еще детали? Я думал, что практически каждый оптимизирующий компилятор в настоящее время использует SSA в качестве IR, что означает, что он использует goto-подобный код внизу.
Мацей Печотка
@MaciejPiechotka Я не инженер компилятора. Да, все современные компиляторы используют SSA в своем промежуточном представлении. Компиляторы предпочитают управляющие конструкции с одним входом и одним выходом, не знаете, как на это влияет использование SSA? Наблюдение за сгенерированным машинным кодом и использованием ресурсов компилятора, а также обсуждения с инженерами компилятора неструктурированного потока управления мешают оптимизировать преобразования кода, вероятно, из-за проблемы «пришедшего». Использование ресурсов (время, память) может оказать негативное влияние на производительность кода, если компилятор решит пропустить оптимизацию как слишком дорогую.
njuffa
12

return, break, continueИ throw/ catchвсе по существу GOTOS - они все передачи управления в другой части кода и все они могут быть реализованы с помощью GOTOS - на самом деле я сделал это один раз в школьном проекте, Паскаля инструктор говорил , насколько лучше Паскаль , чем основной из-за структуры ... так что я должен был быть противоположным ...

Самая важная вещь в Software Engineering (я собираюсь использовать этот термин над Coding для обозначения ситуации, когда кто-то платит вам за создание кодовой базы вместе с другими инженерами, что требует постоянного улучшения и обслуживания), делает код читабельным. Получение этого, чтобы сделать что-то, почти вторично. Ваш код будет написан только один раз, но в большинстве случаев люди будут тратить дни и недели на его пересмотр / переучивание, улучшение и исправление - и каждый раз, когда им (или вам) придется начинать с нуля и пытаться запомнить / выяснить ваш код.

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

По сравнению с аналогичными инструкциями управления потоком GOTO может быть почти так же легко следовать в лучшем виде (одиночное goto, используемое в случае, как вы предлагаете), и кошмар, когда злоупотребляют - и очень легко злоупотреблять ...

Так что после нескольких лет кошмаров со спагетти мы просто сказали «Нет», как сообщество, мы не собираемся это принимать - слишком много людей портят это, если им дают немного свободы - это действительно единственная проблема с ними. Вы можете использовать их ... но даже если это идеальный случай, следующий парень предположит, что вы ужасный программист, потому что вы не понимаете историю сообщества.

Многие другие структуры были разработаны только для того, чтобы сделать ваш код более понятным: функции, объекты, область видимости, инкапсуляция, комментарии (!) ... а также более важные шаблоны / процессы, такие как «СУХОЙ» (предотвращающий дублирование) и «ЯГНИ» (Уменьшение чрезмерного обобщения / усложнения кода) - все это действительно только для того, чтобы СЛЕДУЮЩИЙ парень прочитал ваш код (кто, вероятно, будет вами - после того, как вы забыли большую часть того, что вы делали в первую очередь!)

Билл К
источник
3
Я высказываю это только за предложение: «Самое главное ... сделать код читабельным; заставить его что-то делать почти второстепенно». Я бы сказал это немного иначе; это не столько делает код читабельным, сколько делает код простым . Но в любом случае, это правда, что заставить его что- то делать - это второстепенно.
Wildcard
« , И / все по существу GOTOS» Не согласен, бывшее уважение Догматы структурированного программирования (хотя можно утверждать об исключениях), идти к определенно не делает. В свете этого вопроса это замечание мало что дает. returnbreakcontinuethrowcatch
Эрик
@eric Вы можете смоделировать любое из утверждений с GOTO. Вы можете убедиться, что все GOTO согласуются с принципами структурированного программирования - они просто имеют другой синтаксис и должны, чтобы точно дублировать функциональность, включать другие операции, такие как «если». Преимущество структурированных версий состоит в том, что они ограничены поддержкой только определенных целей - вы ЗНАЕТЕ, когда видите продолжение приблизительно там, где будет расположена цель. Причина, по которой я упомянул это, заключалась в том, чтобы указать, что проблема заключается в злоупотреблении, а не в том, что его нельзя использовать правильно.
Билл К
7

GOTOэто инструмент. Это может быть использовано во благо или во зло.

В старые добрые времена, с Фортраном и Бейсиком, это был почти единственный инструмент.

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

Люди хотели чего-то лучшего, и были изобретены более совершенные структуры управления. Они охватывали большинство случаев использования, и люди, которые были сожжены плохими людьми, GOTOхотели полностью запретить их.

Как ни странно, GOTOне так уж и плохо, когда это редко. Когда вы видите один, вы знаете, что происходит что-то особенное, и легко найти соответствующий ярлык, так как это единственный ярлык поблизости.

Перенесемся в сегодня. Вы преподаватель программирования. Вы можете сказать: «В большинстве случаев вам следует использовать расширенные новые конструкции, но в некоторых случаях простое GOTOможет быть более читабельным». Студенты не поймут этого. Они собираются злоупотреблять, GOTOчтобы сделать нечитаемый код.

Вместо этого вы говорите « GOTOплохо. GOTOЗло. GOTOПровалить экзамен». Студенты будут понимать , что !

Стиг Хеммер
источник
4
Это на самом деле верно для всех устаревших вещей. Глобал. Однобуквенные имена переменных. Самоизменяющийся код. Eval. Даже, я подозреваю, нефильтрованный пользовательский ввод. Как только мы подготовили себя к тому, чтобы избегать таких вещей, как чума, тогда мы находимся в подходящем положении, чтобы оценить, может ли определенное использование, хорошо обозначенное, быть правильным решением конкретной проблемы. До этого мы должны считать их просто запрещенными.
Деви Морган
4

За исключением того goto, что все конструкции потока в PHP (и большинство языков) имеют иерархическую область видимости.

Представьте, что какой-то код проверен косыми глазами:

a;
foo {
    b;
}
c;

Независимо от того, что управление конструкцией fooявляется ( if, whileи т.д.), есть только определенные разрешенные заказы a, bи c.

Вы могли бы иметь a- b- cили a- cили даже a- b- b- b- c. Но вы никогда не могли иметь b- cили a- b- a- c.

... если у вас нет goto.

$a = 1;
first:
echo 'a';
if ($a === 1) {
    echo 'b';
    $a = 2;
    goto first;
}
echo 'c'; 

goto(в частности, в обратном направлении goto) может быть достаточно хлопотным, так что лучше просто оставить его в покое и использовать иерархические, блокированные конструкции потока.

gotoОни имеют место, но в основном как микрооптимизация на языках низкого уровня. ИМО, в PHP нет подходящего места для этого.


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

if(!in_array($ip, $ips, true)) {
    throw new Exception('Not allowed');
}
Пол Дрейпер
источник
2

На языках низкого уровня GOTO неизбежен. Но на высоком уровне этого следует избегать (в случае, если язык поддерживает это), потому что это делает программы более трудными для чтения .

Все сводится к тому, чтобы сделать код более сложным для чтения. Языки высокого уровня необходимы для того, чтобы облегчить чтение кода, чем языки низкого уровня, например, ассемблер или C.

GOTO не вызывает глобального потепления и не вызывает бедность в третьем мире. Это просто затрудняет чтение кода.

Большинство современных языков имеют управляющие структуры, которые делают GOTO ненужным. У некоторых как Java даже нет этого.

Фактически, термин « код спагетти» происходит от сложного, сложного для понимания причин кода неструктурированными ветвящимися структурами.

Тулаинс Кордова
источник
6
gotoМожно сделать код Eaiser для чтения. Когда вы создаете дополнительные переменные и вложенные ветви по сравнению с одним переходом, код становится намного сложнее для чтения и понимания.
Мэтью Уайтед
@ MatthewWhited Возможно, если у вас есть один переход в метод из десяти строк. Но большинство методов не длиной в десять строк, и в большинстве случаев, когда люди используют GOTO, они не используют его «только один раз».
Тулаинс Кордова
2
@MatthewWhited На самом деле термин spaguetti-код происходит от сложного, сложного для понимания кода , вызванного неструктурированными ветвящимися структурами. Или теперь спагетти-код легче красить? Может быть. Винил возвращается, почему бы не GOTO.
Тулаинс Кордова
3
@Tulains Я должен верить, что такие плохие вещи существуют, потому что люди продолжают жаловаться на это, но в большинстве случаев я вижу, gotoчто они не являются примерами запутанного кода спагетти, а скорее довольно простыми вещами, часто эмулирующими шаблоны потока управления в языках, которые не у него нет синтаксиса: два наиболее распространенных примера - разрыв нескольких циклов и пример в OP, где gotoиспользуется для реализации for- else.
1
Неструктурированный код спагетти происходит из языков, где функции / методы не существуют. gotoтакже отлично подходит для таких вещей, как повторная попытка исключения, откат, конечные автоматы.
Мэтью Уайтед
1

Ничего плохого в gotoсамих заявлениях. Неправильны некоторые люди, которые неуместно используют это утверждение.

В дополнение к тому, что сказал JacquesB (обработка ошибок в C), вы используете gotoдля выхода из не вложенного цикла, что вы можете сделать с помощью break. В этом случае вам лучше использовать break.

Но если бы у вас был сценарий с вложенным циклом, то использование gotoбыло бы более элегантным / простым. Например:

$allowed = false;

foreach ($ips as $i) {
    foreach ($ips2 as $i2) {
        if ($ip === $i && $ip === $i2) {
            $allowed = true;
            goto out;
        }
    }
}

out:

if (!$allowed) {
    throw new Exception('Not allowed');
}

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

Бонус: если ваш список IP-адресов невелик, ваш метод подойдет . Но если список растет, знайте, что ваш подход имеет асимптотическую наихудшую сложность времени выполнения O (n) . По мере роста вашего списка вы можете захотеть использовать другой метод, который достигает O (log n) (например, древовидная структура) или O (1) (хеш-таблица без коллизий).

троглодит
источник
6
Я не уверен насчет PHP, но многие языки будут поддерживать использование breakи continueс числом (для разрыва / продолжения такого количества циклов) или меткой (для разрыва / продолжения цикла с этой меткой), любой из которых обычно должен быть предпочтительнее использовать gotoдля вложенных циклов.
8bittree
@ 8bittree хорошая точка. Я не знал, что разрыв PHP так хорош. Я только знаю, что перерыв С не такой уж и причудливый. Разрыв Perl (они называют его последним ) также был похож на C (то есть не такой уж и необычный, как у PHP), но через некоторое время он стал слишком модным. Я думаю, мой ответ становится все менее и менее полезным, так как все больше языков вводят причудливые версии перерыва :)
пещерный человек
3
разрыв со значением глубины не решит проблему без дополнительной переменной. Сама переменная, которая создает дополнительный уровень сложности.
Мэтью Уайтед
Конечно, если у вас есть вложенные циклы, это не значит, что вам нужно переходить, есть и другие способы элегантно справиться с этой ситуацией.
NPSF3000
@ NPSF3000 Не могли бы вы предложить пример вложенного цикла, который можно завершить без использования оператора goto , а также с использованием языка, который не имеет причудливой версии разрыва, которая задает глубину?
пещерный человек
0

С goto я могу писать более быстрый код!

Правда. Не волнует

Goto существует в сборке! Они просто называют это JMP.

Правда. Не волнует

Goto решает проблемы проще.

Правда. Не волнует

В руках дисциплинированного кода разработчика, который использует goto, легче читать.

Правда. Тем не менее, я был тем дисциплинированным программистом. Я видел, что происходит с кодом с течением времени. Gotoначинается нормально. Затем возникает желание повторно использовать кодовые наборы. Довольно скоро я нахожусь в точке останова, не имея ни малейшего понятия, что происходит, даже после просмотра состояния программы. Gotoзатрудняет рассуждения о коде Мы работали очень трудно Создание while, do while, for, for each switch, subroutines, functions, и больше всего потому , что делает этот материал с ifиgoto трудно на мозг.

Так что нет. Мы не хотим смотреть на goto. Конечно, он жив и здоров в двоичном коде, но нам не нужно видеть это в источнике. На самом деле, ifначинает выглядеть немного шатким.

candied_orange
источник
1
«Goto решает проблемы проще». / "Верно. Не волнует." - Я не хотел бы видеть ваш код, где вы сознательно избегаете простых решений в пользу того, что является наиболее расширяемым. (Слышал о YAGNI?)
user253751
1
@Wildcard if и goto - это очень простые способы решения проблем, которые лучше всего решать другими способами. Они низко висящие фрукты. Это не о конкретном языке. Gotoпозволяет вам абстрагировать проблему, сделав ее немного другой проблемой кода. Ifпозволяет вам выбрать эту абстракцию. Есть лучшие способы абстрагирования и лучшие способы выбора абстракции. Полиморфизм для одного.
candied_orange
2
Хотя я согласен с вами, это плохо сформулированный ответ. «Правда, все равно» не является убедительным аргументом ни для чего. Я думаю, что ваше основное сообщение таково: хотя goto привлекает людей, которые предпочитают использовать эффективные и мощные инструменты, это приводит к удивительно большому количеству потерянного времени впустую, даже если принять меры предосторожности.
Артелий
1
@artelius Тема «правда, все равно» не должна быть убедительной. Он призван проиллюстрировать многие моменты, которые я уступлю, и все же буду опровергать это. Поэтому спорить со мной по этим вопросам бессмысленно. Так как это не моя точка зрения. Вникнуть в суть?
candied_orange
1
Я просто считаю, что хороший ответ не только излагает ваше мнение, но и объясняет его, и позволяет читателю самому принять решение. В настоящее время неясно, почему положительных моментов goto недостаточно, чтобы перевесить его проблемы. Большинство из нас потратили много часов на то, чтобы найти ошибки, не связанные с goto. Это не единственная конструкция, о которой трудно рассуждать. Кто-то, кто задает этот вопрос, вероятно, менее опытен и нуждается в вещах в перспективе.
Артелиус
-1

Языки ассемблера обычно имеют только условные / безусловные переходы (эквивалент GOTO. В более старых реализациях FORTRAN и BASIC не было операторов блока управления, кроме подсчитанной итерации (цикл DO), оставляя весь другой поток управления для IF и GOTO. Цикл DO в эти языки заканчивались числовым выражением, в результате чего код, написанный для этих языков, мог быть, и часто был трудным для следования и подвержен ошибкам.

Чтобы подчеркнуть суть, есть изобретательно выдуманная фраза « ПРИХОДИТЕ ОТ ».

Практически нет необходимости использовать GOTO в таких языках, как C, C ++, C #, PASCAL, Java и т. Д .; можно использовать альтернативные конструкции, которые почти наверняка будут такими же эффективными и гораздо более ремонтопригодными. Это правда, что один GOTO в исходном файле не будет проблемой. Проблема в том, что не требуется много усилий, чтобы сделать блок кода сложным для отслеживания и подверженным ошибкам в обслуживании. Вот почему общепринятая мудрость - избегать GOTO, когда это возможно.

Эта статья в Википедии об утверждении goto может быть полезна

Zenilogix
источник