O que há de tão ruim no goto quando é usado nesses casos óbvios e relevantes?

40

Eu sempre soube que isso gotoé algo ruim, trancado em um porão em algum lugar para nunca ser visto de vez, mas encontrei hoje um exemplo de código que faz todo sentido goto.

Eu tenho um IP no qual preciso verificar se está dentro de uma lista de IPs e prosseguir com o código, caso contrário, lance uma exceção.

<?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:

...

Se eu não usar goto, tenho que usar alguma variável como

$allowed = false;

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

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

Minha pergunta é o que há de tão ruim gotoquando é usado em casos tão óbvios e imo relevantes?

php_nub_qq
fonte
Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
maple_shaft

Respostas:

120

O GOTO em si não é um problema imediato, são as máquinas de estado implícitas que as pessoas tendem a implementar com ele. No seu caso, você deseja um código que verifique se o endereço IP está na lista de endereços permitidos, portanto

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

portanto, seu código deseja verificar uma condição. O algoritmo para implementar essa verificação não deve ser motivo de preocupação aqui, no espaço mental do seu programa principal, a verificação é atômica. É assim que deve ser.

Mas se você colocar o código que faz a verificação no seu programa principal, você o perde. Você introduz um estado mutável, explicitamente:

$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');
}

onde $list_contains_ipé sua única variável de estado ou implicitamente:

                             # 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

Como você vê, há uma variável de estado não declarada na construção GOTO. Isso não é um problema em si, mas essas variáveis ​​de estado são como pedras: carregar uma não é difícil, carregar uma sacola cheia delas fará você suar. Seu código não permanecerá o mesmo: no próximo mês, você será solicitado a diferenciar os endereços público e privado. No mês seguinte, seu código precisará oferecer suporte a intervalos de IP. No próximo ano, alguém solicitará que você suporte endereços IPv6. Em pouco tempo, seu código ficará assim:

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.

E quem precisar depurar esse código amaldiçoará você e seus filhos.

Dijkstra coloca assim:

O uso desenfreado da instrução go to tem como conseqüência imediata que fica terrivelmente difícil encontrar um conjunto significativo de coordenadas para descrever o progresso do processo.

E é por isso que o GOTO é considerado prejudicial.

wallenborn
fonte
22
Essa $list_contains_ip = false;afirmação parece extraviada
Bergi
11
Uma bolsa cheia de pedras é fácil, eu tenho uma bolsa conveniente para segurá-las. : p
whatsisname 26/08/16
13
@ Bergi: Você está certo. Isso mostra como é fácil estragar essas coisas.
Wallenborn
6
@whatsisname Essa sacola é chamada de função / classe / pacote para armazená-las. usar gotos é como fazer malabarismos com eles e jogar a sacola fora.
Falco
5
Eu amo a citação de Dijkstra, eu não tinha ouvido dessa maneira, mas é um ponto muito bom. Em vez de ter um fluxo praticamente de cima para baixo, de repente você tem algo que pode saltar por toda a página aleatoriamente. Colocando isso de forma sucinta é bastante impressionante.
Bill K
41

Existem alguns casos de uso legítimos para GOTO. Por exemplo, para manipulação e limpeza de erros em C ou para implementar algumas formas de máquinas de estado. Mas este não é um desses casos. O segundo exemplo é o IMHO mais legível, mas ainda mais legível seria extrair o loop para uma função separada e retornar quando você encontrar uma correspondência. Ainda melhor seria (no pseudocódigo, eu não sei a sintaxe exata):

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

Então, o que há de tão ruim GOTOnisso? A programação estruturada usa funções e estruturas de controle para organizar o código, para que a estrutura sintática reflita a estrutura lógica. Se algo for executado apenas condicionalmente, ele aparecerá em um bloco de instruções condicionais. Se algo for executado em um loop, ele aparecerá em um bloco de loop. GOTOpermite contornar a estrutura sintática saltando arbitrariamente, tornando o código muito mais difícil de seguir.

Obviamente, se você não tiver outra escolha GOTO, mas se o mesmo efeito puder ser alcançado com funções e estruturas de controle, é preferível.

JacquesB
fonte
5
@jameslarge it's easier to write good optimizing compilers for "structured" languages.Cuidado para elaborar? Como um contra-exemplo, o pessoal da Rust introduziu o MIR , uma representação intermediária no compilador que substitui especificamente loops, continuações, quebras e outros por gotos, porque é mais fácil verificar e otimizar.
precisa saber é o seguinte
6
"se você não tiver outra opção, use o GOTO" Isso seria extremamente raro. Sinceramente, não consigo pensar em um caso em que você não tem outra escolha, fora de restrições completamente ridículas, impedindo a refatoração do código existente ou bobagens semelhantes.
precisa saber é
8
Além disso, a IMO, emulando a gotocom um ninho de ratos de sinalizadores e condicionais (como no segundo exemplo do OP), é muito menos legível do que juts usando a goto.
3
@ 8bittree: A programação estruturada destina-se ao idioma de origem, não ao idioma de destino do compilador. O idioma de destino para os compiladores nativos são as instruções da CPU, que decididamente não são "estruturadas" no sentido da linguagem de programação.
Robert Harvey
4
@ 8bittree A resposta para sua pergunta sobre o MIR está no link que você forneceu: "Mas é bom ter essa construção no MIR, porque sabemos que ele será usado apenas de maneiras específicas, como expressar um loop ou uma interrupção . " Em outras palavras, como o goto não é permitido no Rust, eles sabem que é estruturado e a versão intermediária com o gotos também. Por fim, o código precisa ir para os comandos da máquina. O que recebo do seu link é que eles estão simplesmente adicionando uma etapa incremental na conversão do idioma de alto nível para o de baixo nível.
JimmyJames
17

Como outros já disseram, o problema não está no gotopróprio; o problema está em como as pessoas usam gotoe em como isso pode dificultar o entendimento e a manutenção do código.

Suponha o seguinte trecho de código:

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

Para que valor é impresso i? Quando é impresso? Até que você responda a todas as instâncias da goto labelsua função, você não poderá saber. A simples presença desse rótulo destrói sua capacidade de depurar código por meio de uma simples inspeção. Para pequenas funções com uma ou duas ramificações, não há muito problema. Para funções não pequenas ...

No início dos anos 90, recebemos uma pilha de código C que dirigia uma tela gráfica em 3D e nos mandava fazê-la funcionar mais rapidamente. Eram apenas cerca de 5000 linhas de código, mas todas estavam dentro main, e o autor usou cerca de 15 ou mais gotoramificações nas duas direções. Este era um código ruim , para começar, mas a presença deles gototornava tudo muito pior. O meu colega de trabalho levou cerca de duas semanas para descobrir o fluxo de controle. Melhor ainda, esses gotoresultados resultaram em um código tão fortemente associado a si mesmo que não pudemos fazer nenhuma alteração sem quebrar alguma coisa.

Tentamos compilar com a otimização de nível 1, e o compilador consumiu toda a RAM disponível, depois toda a troca disponível e depois entrou em pânico no sistema (que provavelmente não tinha nada a ver com o gotopróprio s, mas eu gosto de contar essa história).

No final, demos ao cliente duas opções - vamos reescrever tudo do zero ou comprar hardware mais rápido.

Eles compraram hardware mais rápido.

Regras do Bode para usar goto:

  1. Ramificar apenas para frente;
  2. Não ignorar as estruturas de controle (ou seja, não se ramificar para o corpo de um ifou forou whiledeclaração);
  3. Não use gotono lugar de uma estrutura de controle

Há casos em que a goto é a resposta certa, mas eles são raros (romper um loop profundamente aninhado é o único lugar em que eu o uso).

EDITAR

Expandindo essa última declaração, aqui está um dos poucos casos de uso válidos para goto. Suponha que temos a seguinte função:

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;
}

Agora, temos um problema - e se uma das mallocchamadas falhar no meio? Por mais improvável que seja um evento, não queremos retornar uma matriz parcialmente alocada, nem queremos apenas sair da função com um erro; queremos limpar a nós mesmos e desalocar qualquer memória parcialmente alocada. Em um idioma que lança uma exceção em uma alocação incorreta, isso é bastante simples - basta escrever um manipulador de exceções para liberar o que já foi alocado.

Em C, você não possui manipulação de exceção estruturada; você deve verificar o valor de retorno de cada mallocchamada e executar a ação apropriada.

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;
}

Podemos fazer isso sem usar goto? É claro que podemos - isso requer apenas um pouco de contabilidade extra (e, na prática, esse é o caminho que eu seguiria). Mas, se você está procurando lugares onde o uso de um gotonão é imediatamente um sinal de má prática ou design, esse é um dos poucos.

John Bode
fonte
Eu gosto dessas regras. Eu ainda não usaria gotomesmo em conformidade com estas regras, eu não iria usá-lo em toda a menos que seja a única forma de ramificação disponível no idioma, mas eu posso ver que não seria demasiado de um pesadelo para debug gotoé se eles foram escritos de acordo com essas regras.
Curinga
se você precisar sair de um laço profundamente aninhada, você simplesmente precisa para fazer esse loop outra função e retorno
bunyaCloven
6
Como alguém uma vez resumiu para mim: "Não é um problema básico, é um problema proveniente de". Como especialista em otimização de software, concordo que o fluxo de controle não estruturado pode gerar compiladores (e humanos!) Para um loop. Certa vez, passei horas decifrando uma máquina de estados simples (quatro de cinco estados) em uma função BLAS, que usava várias formas de GOTO, incluindo os famosos gotos aritméticos e atribuídos a Fortran, se bem me lembro.
njuffa
@njuffa "Como especialista em otimização de software, concordo que o fluxo de controle não estruturado pode gerar compiladores (e humanos!) para um loop." - mais algum detalhe? Eu pensei que praticamente todo compilador de otimização hoje em dia usa SSA como IR, o que significa que está usando código semelhante a goto por baixo.
Maciej Piechotka
@MaciejPiechotka Eu não sou um engenheiro de compilador. Sim, todos os compiladores modernos parecem usar SSA em suas representações intermediárias. Os compiladores preferem construções de controle de entrada única e saída única, sem saber como o uso do SSA se encaixa nisso? Observando o código de máquina gerado e o uso de recursos do compilador, e as discussões com os engenheiros do compilador, o fluxo de controle não estruturado interfere na otimização das transformações de código, provavelmente devido ao problema "proveniente". O uso de recursos (tempo, memória) pode ter um impacto negativo no desempenho do código se o compilador decidir ignorar uma otimização por ser muito cara.
Njuffa
12

return, break, continueE throw/ catchsão essencialmente gotos - todos eles de controle de transferência para outro pedaço de código e tudo poderia ser implementado com gotos - na verdade eu fiz isso uma vez em um projeto da escola, um instrutor PASCAL estava dizendo quanto melhor Pascal era de básico por causa da estrutura ... então eu tinha que ser contrário ...

A coisa mais importante sobre engenharia de software (vou usar esse termo sobre codificação para se referir a uma situação em que você está sendo pago por alguém para criar uma base de código junto com outros engenheiros que exigem melhoria e manutenção contínuas) é tornar o código legível - - fazer algo é quase secundário. Seu código será escrito apenas uma vez, mas, na maioria dos casos, as pessoas passarão dias e semanas revisitando / reaprendendo, melhorando e corrigindo - e toda vez que elas (ou você) terão que começar do zero e tentar lembrar / descobrir seu código.

A maioria dos recursos que foram adicionados aos idiomas ao longo dos anos é tornar o software mais sustentável, não mais fácil de escrever (embora alguns idiomas sigam nessa direção - geralmente causam problemas de longo prazo ...).

Comparado a declarações de controle de fluxo semelhantes, os GOTOs podem ser quase tão fáceis de seguir da melhor maneira possível (um único pulo usado em um caso como o sugerido) e um pesadelo quando abusados ​​- e são facilmente abusados ​​...

Então, depois de lidar com pesadelos de espaguete por alguns anos, apenas dissemos "Não", como comunidade, não vamos aceitar isso - muitas pessoas estragam tudo se houver um pouco de espaço - esse é realmente o único problema com eles. Você pode usá-los ... mas, mesmo que seja o caso perfeito, o próximo cara assumirá que você é um péssimo programador, porque você não entende a história da comunidade.

Muitas outras estruturas foram desenvolvidas apenas para tornar seu código mais compreensível: Funções, Objetos, Escopo, Encapsulamento, Comentários (!) ... bem como padrões / processos mais importantes como "DRY" (impedindo a duplicação) e "YAGNI" (Reduzindo a generalização / complicação excessiva de código) - tudo realmente importa apenas para o PRÓXIMO cara ler seu código (quem provavelmente será você - depois que você esqueceu a maior parte do que fez em primeiro lugar!)

Bill K
fonte
3
Estou votando isso apenas para a frase "A coisa mais importante ... é tornar o código legível; fazê-lo fazer algo é quase secundário". Eu diria isso apenas um pouco diferente; não é apenas tornar o código legível , mas simplificar o código . Mas de qualquer maneira, é tão verdade que fazê-lo fazer algo é secundário.
Curinga
" , E / são essencialmente gotos" Discordo, o ex respeito os princípios da programação estruturada (embora você poderia argumentar sobre exceções), go-to definitivamente não faz. À luz dessa questão, pouco se ganha com essa observação. returnbreakcontinuethrowcatch
Eric
@eric Você pode modelar qualquer uma das declarações com GOTOs. Você pode garantir que todos os GOTOs estejam de acordo com princípios de programação estruturados - eles simplesmente têm uma sintaxe diferente e devem, para duplicar exatamente a funcionalidade, incluir outras operações como "se". A vantagem das versões estruturadas é que elas são restritas a dar suporte apenas a determinados destinos - você SABE quando vê uma continuação aproximadamente onde o destino será localizado. A razão pela qual mencionei foi apontar que é o abuso que é o problema, não que não possa ser usado corretamente.
Bill K
7

GOTOé uma ferramenta. Pode ser usado para o bem ou para o mal.

Nos velhos tempos ruins, com FORTRAN e BASIC, era quase a única ferramenta.

Ao analisar o código daqueles dias, quando você vê um, GOTOprecisa descobrir por que ele está lá. Pode fazer parte de um idioma padrão que você pode entender rapidamente ... ou pode fazer parte de alguma estrutura de controle de pesadelo que nunca deveria ter sido. Você não sabe até olhar, e é fácil estar enganado.

As pessoas queriam algo melhor e estruturas de controle mais avançadas foram inventadas. Eles cobriam a maioria dos casos de uso, e as pessoas que foram queimadas por maus GOTOqueriam bani-los completamente.

Ironicamente, GOTOnão é tão ruim quando é raro. Quando você vê um, sabe que há algo especial acontecendo e é fácil encontrar o rótulo correspondente, pois é o único rótulo por perto.

Avanço rápido de hoje. Você é um professor ensinando programação. Você poderia dizer "Na maioria dos casos, você deve usar as novas construções avançadas, mas, em alguns casos, uma simples GOTOpode ser mais legível". Os alunos não vão entender isso. Eles vão abusar GOTOpara criar código ilegível.

Em vez disso, você diz " GOTOruim. GOTOMal. GOTOFalha no exame". Os alunos entenderão isso !

Stig Hemmer
fonte
4
Isso é verdade para todas as coisas obsoletas. Globals. Nomes de variáveis ​​de uma letra. Código auto-modificável. Eval. Suspeito que até mesmo a entrada do usuário não filtrada. Depois de nos condicionarmos a evitar coisas como a praga, estamos em uma posição adequada para avaliar se um certo uso deles, bem sinalizado, pode ser a solução correta para um problema específico. Antes disso, é melhor tratá-los como simplesmente banidos.
Dewi Morgan
4

Com exceção de goto, todas as construções de fluxo no PHP (e na maioria das linguagens) têm escopo hierarquicamente.

Imagine algum código examinado através dos olhos apertados:

a;
foo {
    b;
}
c;

Independentemente do que construção de controlo fooé ( if, while, etc), há apenas certos pedidos permitidos para a, be c.

Você pode ter a- b- c, ou a- c, ou mesmo a- b- b- b- c. Mas você nunca poderia ter b- cou a- b- a- c.

... a menos que você tenha goto.

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

goto(em particular ao contrário goto) pode ser problemático o suficiente para deixá-lo em paz e usar construções de fluxo hierárquicas e bloqueadas.

gotos têm um lugar, mas principalmente como micro-otimizações em idiomas de baixo nível. IMO, não há um bom lugar para isso em PHP.


Para sua informação, o código de exemplo pode ser escrito ainda melhor do que qualquer uma das suas sugestões.

if(!in_array($ip, $ips, true)) {
    throw new Exception('Not allowed');
}
Paul Draper
fonte
2

Em idiomas de baixo nível, o GOTO é inevitável. Porém, em alto nível, isso deve ser evitado (no caso de o idioma suportar), pois dificulta a leitura dos programas .

Tudo se resume a tornar o código mais difícil de ler. Idiomas de alto nível são supostos para facilitar a leitura do código do que idiomas de baixo nível como, por exemplo, assembler ou C.

O GOTO não causa aquecimento global nem causa pobreza no terceiro mundo. Isso apenas torna o código mais difícil de ler.

A maioria das linguagens modernas possui estruturas de controle que tornam o GOTO desnecessário. Alguns como Java nem sequer o têm.

De fato, o termo código spaguetti vem de causas de código complicadas e difíceis de seguir por estruturas de ramificação não estruturadas.

Tulains Córdova
fonte
6
gotopode fazer código ansioso para ler. Quando você criou variáveis ​​extras e ramificações aninhadas versus um único salto, o código é muito mais difícil de ler e entender.
Matthew Whited
@ Matthewhewited Talvez se você tiver um único goto em um método de dez linhas. Mas a maioria dos métodos não tem dez linhas e, na maioria das vezes, quando as pessoas usam o GOTO, não o usam "apenas desta vez".
Tulains Córdova
2
@MatthewWhited De fato, o termo código spaguetti vem de código complicado e difícil de seguir causado por estruturas de ramificação não estruturadas. Ou o código spaguetti é mais fácil de ser vermelho agora? Talvez. O vinil está voltando, por que não o GOTO?
Tulains Córdova
3
@Tulains Eu tenho que acreditar que essas coisas ruins existem porque as pessoas continuam reclamando, mas na maioria das vezes eu vejo gotosurgir não são exemplos de códigos complicados de espaguete, mas coisas bastante simples, muitas vezes simulando padrões de fluxo de controle em idiomas que não tem a sintaxe: os dois exemplos mais comuns são romper com vários loops e o exemplo no OP onde gotoé usado para implementar for- else.
11
O código espaguete não estruturado vem de linguagens onde não existem funções / métodos. gototambém é ótimo para itens como repetição de exceção, reversão e máquinas de estado.
Matthew Whited
1

Nada de errado com as gotopróprias declarações. Os erros estão com algumas das pessoas que usam inadequadamente a declaração.

Além do que JacquesB disse (tratamento de erros em C), você está usando gotopara sair de um loop não aninhado, algo que você pode fazer usando break. Nesse caso, é melhor você usar break.

Mas se você tivesse um cenário de loop aninhado, o uso gotoseria mais elegante / simples. Por exemplo:

$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');
}

O exemplo acima não faz sentido no seu problema específico, porque você não precisa de um loop aninhado. Mas espero que você veja apenas parte do loop aninhado.

Ponto bonous: se sua lista de IPs é pequena, seu método está correto . Mas se a lista aumentar, saiba que sua abordagem tem uma pior complexidade assintótica de tempo de execução de O (n) . À medida que sua lista cresce, convém usar um método diferente que atinja O (log n) (como uma estrutura em árvore) ou O (1) (uma tabela de hash sem colisões).

homem das cavernas
fonte
6
Não tenho certeza sobre o PHP, mas muitas linguagens suportam o uso breake continuecom um número (para interromper / continuar tantas camadas de loops) ou um rótulo (para interromper / continuar o loop com esse rótulo), um dos quais geralmente deve ser preferível a usar gotopara loops aninhados.
precisa saber é o seguinte
@ 8bittree bom ponto. Eu não sabia que a quebra do PHP é tão chique. Só sei que a pausa de C não é tão chique. O intervalo do Perl (eles chamam de último ) também costumava ser semelhante ao do C (ou seja, não é tão chique quanto o do PHP), mas tornou-se chique depois de algum ponto. Acho que minha resposta está ficando cada vez menos útil como mais idiomas estão introduzindo versões fantasia de pausa :)
homem das cavernas
3
uma quebra com um valor de profundidade não resolveria o problema sem a variável extra. Uma variável em si mesma que cria um nível extra de complexidade.
Matthew Whited
É claro que, apenas porque você tem loops aninhados não significa que você precisa ir, existem outras maneiras de lidar com essa situação com elegância.
NPSF3000 27/08/16
@ NPSF3000 Você poderia oferecer um exemplo de loop aninhado que você pode sair sem usar uma instrução goto , além de usar uma linguagem que não possui uma versão sofisticada de quebra que especifique a profundidade?
homem das cavernas
0

Com goto eu posso escrever código mais rápido!

Verdade. Não se importe.

Goto existe na montagem! Eles apenas chamam de jmp.

Verdade. Não se importe.

Ir para resolve problemas de maneira mais simples.

Verdade. Não se importe.

Nas mãos de um código de desenvolvedor disciplinado que usa goto pode ser mais fácil de ler.

Verdade. No entanto, eu tenho sido esse codificador disciplinado. Eu já vi o que acontece com o código ao longo do tempo. Gotocomeça bem. Então surge o desejo de reutilizar o código. Logo, eu me vejo em um ponto de interrupção sem nenhuma pista do que está acontecendo, mesmo depois de analisar o estado do programa. Gototorna difícil raciocinar sobre código. Temos trabalhado criação realmente difícil while, do while, for, for each switch, subroutines, functions, e mais tudo porque fazendo essas coisas com ife gotoé difícil para o cérebro.

Então não. Nós não queremos olhar goto. Claro que está vivo e bem no binário, mas não precisamos ver isso na fonte. De fato, ifestá começando a parecer um pouco instável.

candied_orange
fonte
11
"Ir para resolver problemas de maneira mais simples." / "Verdade. Não se importe." - Eu odiaria ver seu código onde você evita deliberadamente soluções simples em favor do que é mais extensível. (Heard de YAGNI?)
user253751
11
@Wildcard if e goto são maneiras muito simples de resolver problemas melhor resolvidos de outras maneiras. Eles são baixos frutos pendurados. Não é sobre o idioma específico. Gotopermite abstrair um problema, tornando-o outro problema de outro código. Ifpermite escolher essa abstração. Existem maneiras melhores de abstrair e maneiras melhores de escolher a abstração. Polimorfismo para um.
candied_orange
2
Embora eu concorde com você, esta é uma resposta mal formulada. "Verdade, não ligue" não é um argumento convincente para nada. Penso que a sua mensagem principal é a seguinte: embora o goto seja atraente para as pessoas que preferem usar ferramentas eficientes e poderosas, isso leva a uma quantidade surpreendentemente enorme de tempo perdido posteriormente, mesmo quando tomamos cuidado.
Artelius 26/08/16
11
@artelius O tema "verdadeiro, não me importo" não é convincente. Ele serve para ilustrar os muitos pontos que concordo em ir e ainda vou contra isso. Assim, discutir esses pontos comigo é inútil. Desde que esse não é o meu ponto. Entenda a ideia?
candied_orange
11
Apenas acredito que uma boa resposta não apenas exprime a sua opinião, mas também a explica e permite que o leitor faça seu próprio julgamento. Tal como está, não está claro por que os bons pontos de Goto não são suficientes para superar seus problemas. A maioria de nós passou horas puxando os cabelos tentando encontrar bugs que não envolvem goto. Não é o único construto difícil de raciocinar. Alguém que faz essa pergunta provavelmente é muito menos experiente e precisa de coisas em perspectiva.
Artelius 26/08/16
-1

As linguagens assembly geralmente têm apenas saltos condicionais / incondicionais (o equivalente a GOTO. Implementações mais antigas do FORTRAN e BASIC não tinham instruções de bloco de controle além de uma iteração contada (o loop DO), deixando todo o outro fluxo de controle para IFs e GOTOs. esses idiomas foram encerrados por uma declaração numerada e, como resultado, o código escrito para esses idiomas poderia ser, e muitas vezes era, difícil de seguir e propenso a erros.

Para enfatizar o argumento, existe a declaração " COME FROM " , que foi inventada com facilidade .

Praticamente não há necessidade de usar o GOTO em linguagens como C, C ++, C #, PASCAL, Java, etc .; podem ser usadas construções alternativas que quase certamente serão igualmente eficientes e muito mais sustentáveis. É verdade que um GOTO em um arquivo de origem não será um problema. O problema é que não é preciso muito para dificultar o acompanhamento de uma unidade de código e manter o erro. É por isso que a sabedoria aceita é evitar o GOTO sempre que possível.

Este artigo da wikipedia sobre a declaração goto pode ser útil

Zenilogix
fonte