Todo mundo está ciente das Cartas de Dijkstra para o editor: vá para a declaração considerada prejudicial (também aqui transcrição .html e aqui .pdf) e houve um esforço formidável desde então para evitar a declaração goto sempre que possível. Embora seja possível usar goto para produzir um código constante e inatingível, ele permanece nas linguagens de programação modernas . Mesmo a estrutura avançada de controle de continuação no Scheme pode ser descrita como um goto sofisticado.
Que circunstâncias justificam o uso do goto? Quando é melhor evitar?
Como uma pergunta de acompanhamento: C fornece um par de funções, setjmp e longjmp, que fornecem a capacidade de ir não apenas dentro do quadro de pilha atual, mas dentro de qualquer um dos quadros de chamada. Devem ser considerados tão perigosos quanto ir? Mais perigoso?
O próprio Dijkstra lamentou esse título, pelo qual não era responsável. No final do EWD1308 (também aqui .pdf), ele escreveu:
Finalmente, uma pequena história para o registro. Em 1968, as Comunicações da ACM publicaram um texto meu sob o título " A declaração goto considerada prejudicial ", que em anos posteriores seria mais frequentemente referenciada, lamentavelmente, no entanto, muitas vezes por autores que não viram mais do que isso. título, que se tornou uma pedra angular da minha fama ao se tornar um modelo: veríamos todos os tipos de artigos sob o título "X considerado prejudicial" para quase qualquer X, incluindo um intitulado "Dijkstra considerado prejudicial". Mas o que tinha acontecido? Eu enviei um artigo com o título " Um caso contra a declaração goto", que, para acelerar sua publicação, o editor havia mudado para uma" carta ao editor "e, no processo, ele havia lhe dado um novo título de sua própria invenção! O editor era Niklaus Wirth.
Um artigo clássico bem pensado sobre esse tópico, a ser comparado ao de Dijkstra, é a Programação Estruturada com ir para Declarações , de Donald E. Knuth. A leitura ajuda a restabelecer o contexto e uma compreensão não dogmática do assunto. Neste artigo, a opinião de Dijkstra sobre este caso é relatada e é ainda mais forte:
Donald E. Knuth: Acredito que, ao apresentar tal opinião, não discordo totalmente das idéias de Dijkstra, pois ele escreveu recentemente o seguinte: "Por favor, não caia na armadilha de acreditar que sou terrivelmente dogmático sobre [o vá para a declaração]. Tenho a desconfortável sensação de que outros estão criando uma religião a partir dela, como se os problemas conceituais da programação pudessem ser resolvidos com um único truque, com uma forma simples de disciplina de codificação! "
fonte
goto
.goto
: hackear ferramentas de programação estruturada para implementar agoto
.Respostas:
As seguintes declarações são generalizações; Embora seja sempre possível alegar exceção, geralmente (na minha experiência e na minha humilde opinião) não vale a pena arriscar.
Notas de rodapé para o acima:
Em relação ao ponto 2, considere o seguinte código:
No ponto "faça alguma coisa" no código, podemos afirmar com alta confiança que
a
é maior queb
. (Sim, estou ignorando a possibilidade de estouro de número inteiro não capturado. Não vamos atolar um exemplo simples.)Por outro lado, se o código tivesse lido desta maneira:
A multiplicidade de maneiras de chegar ao rótulo 10 significa que temos que trabalhar muito mais para termos confiança nas relações entre
a
eb
nesse momento. (De fato, no caso geral, é indecidível!)Em relação ao ponto 4, toda a noção de "ir a algum lugar" no código é apenas uma metáfora. Nada está realmente "indo" a lugar algum dentro da CPU, exceto elétrons e fótons (pelo calor residual). Às vezes desistimos de uma metáfora para outra mais útil. Lembro-me de ter encontrado (algumas décadas atrás!) Um idioma em que
foi implementado em uma máquina virtual compilando a ação-1 e a ação-2 como rotinas sem parâmetros fora de linha e, em seguida, usando um único código de operação da VM de dois argumentos que usava o valor booleano da condição para chamar um ou outro. O conceito era simplesmente "escolha o que chamar agora" em vez de "vá aqui ou vá lá". Novamente, apenas uma mudança de metáfora.
fonte
true
efalse
são de tipos diferentes), e cada ramo de um if / else é basicamente um lambda.goto
em uma linguagem de programação moderna (Go) stackoverflow.com/a/11065563/3309046 .Um colega meu disse que a única razão para usar um GOTO é se você se programou tão longe em um canto que é a única saída. Em outras palavras, projete com antecedência e você não precisará usar um GOTO posteriormente.
Eu pensei que esse quadrinho ilustra que lindamente "eu poderia reestruturar o fluxo do programa ou usar um pequeno 'GOTO'". Um GOTO é uma saída fraca quando você tem um design fraco. Velociraptores atacam os fracos .
fonte
Às vezes, é válido usar o GOTO como uma alternativa ao tratamento de exceções em uma única função:
O código COM parece cair nesse padrão com bastante frequência.
fonte
Só me lembro de usar um goto uma vez. Eu tinha uma série de cinco loops contados aninhados e precisava ser capaz de romper toda a estrutura desde o início, com base em determinadas condições:
Eu poderia ter declarado facilmente uma variável de quebra booleana e a usado como parte do condicional para cada loop, mas nesse caso eu decidi que um GOTO era tão prático quanto legível.
Nenhum velociraptor me atacou.
fonte
goto
e nos deu programação estruturada também rejeitou retornos antecipados, pelo mesmo motivo. Tudo se resume a quão legível o código é, quão claramente ele expressa a intenção do programador. Criar uma função com nenhum outro objetivo além de evitar o uso de uma palavra-chave maligna resulta em má coesão: a cura é pior que a doença.goto
, pode- se especificar explicitamente o destino. Combreak 5;
, (1) tenho que contar os fechamentos de loop para encontrar o destino; e (2) se a estrutura do loop mudar, poderá ser necessário alterar esse número para manter o destino correto. Se eu vou evitargoto
, o ganho deve ser não ter que rastrear manualmente coisas assim.Nós já tivemos essa discussão e eu mantenho meu argumento .
Além disso, estou farta de pessoas que descrevem estruturas de linguagem de alto nível como "
goto
disfarçadas" porque elas claramente não entendem nada . Por exemplo:Isso é um absurdo completo. Toda estrutura de controle pode ser implementada em termos de,
goto
mas essa observação é totalmente trivial e inútil.goto
não é considerado prejudicial por causa de seus efeitos positivos, mas por suas consequências negativas e estas foram eliminadas pela programação estruturada.Da mesma forma, dizer “GOTO é uma ferramenta e, como todas as ferramentas, pode ser usada e abusada” está completamente errado. Nenhum trabalhador da construção civil moderno usaria uma pedra e afirmaria que "é uma ferramenta". Rochas foram substituídas por martelos.
goto
foi substituído por estruturas de controle. Se o trabalhador da construção estivesse preso na natureza sem um martelo, é claro que ele usaria uma pedra. Se um programador precisar usar uma linguagem de programação inferior que não possua o recurso X, é claro que talvez seja necessário usá-logoto
. Mas se ela o usa em qualquer outro lugar, em vez do recurso de idioma apropriado, ela claramente não entende o idioma corretamente e o usa incorretamente. É realmente tão simples quanto isso.fonte
goto
. Você está certo na medida emgoto
que não proponho um argumento em si - eu não pretendia -, então não há perguntas.Goto está extremamente baixo na minha lista de itens a serem incluídos em um programa apenas por isso. Isso não significa que é inaceitável.
Ir pode ser bom para máquinas de estado. Uma instrução switch em um loop é (em ordem de importância típica): (a) não é realmente representativa do fluxo de controle, (b) é feia, (c) é potencialmente ineficiente, dependendo do idioma e do compilador. Então você acaba escrevendo uma função por estado e fazendo coisas como "return NEXT_STATE;" que até parecem goto.
Concedido, é difícil codificar máquinas de estado de uma maneira que as torne fáceis de entender. No entanto, nenhuma dessas dificuldades está relacionada ao uso do goto, e nada disso pode ser reduzido usando estruturas de controle alternativas. A menos que seu idioma tenha uma construção de 'máquina de estado'. O meu não.
Nas raras ocasiões em que seu algoritmo é realmente mais compreensível em termos de um caminho através de uma sequência de nós (estados) conectados por um conjunto limitado de transições permitidas (gotos), em vez de por qualquer fluxo de controle mais específico (loops, condicionais, outros enfeites ), isso deve ser explícito no código. E você deve desenhar um diagrama bonito.
setjmp / longjmp pode ser bom para implementar exceções ou comportamento semelhante a exceção. Embora não sejam universalmente elogiadas, as exceções geralmente são consideradas uma estrutura de controle "válida".
setjmp / longjmp são 'mais perigosos' do que o goto, no sentido de que são mais difíceis de usar corretamente, não importa de maneira compreensível.
Sair do C não tornaria mais fácil escrever um bom código em C. Na verdade, seria melhor não entender que C deveria ser capaz de agir como uma linguagem assembler glorificada.
Em seguida, serão "indicadores considerados prejudiciais" e, em seguida, "digitação de pato considerados prejudiciais". Então, quem ficará para defendê-lo quando eles removerem sua construção de programação insegura? Eh?
fonte
No Linux: Usando goto No Kernel Code no Kernel Trap, há uma discussão com Linus Torvalds e um "novato" sobre o uso de GOTOs no código Linux. Há alguns pontos muito bons lá e Linus se veste dessa arrogância habitual :)
Algumas passagens:
-
-
fonte
goto cleanup_and_exit
é um dos poucos "bons" usos de Goto deixou agora que temosfor
,while
eif
para administrar nosso fluxo de controle. Veja também: programmers.stackexchange.com/a/154980Em C,
goto
funciona apenas dentro do escopo da função atual, que tende a localizar possíveis bugs.setjmp
elongjmp
são muito mais perigosos, sendo não locais, complicados e dependentes da implementação. Na prática, porém, são muito obscuros e incomuns para causar muitos problemas.Eu acredito que o perigo de
goto
em C é muito exagerado. Lembre-se de que osgoto
argumentos originais ocorreram nos dias de idiomas como o BASIC à moda antiga, onde os iniciantes escreviam código espaguete como este:Aqui, Linus descreve um uso apropriado de
goto
: http://www.kernel.org/doc/Documentation/CodingStyle (capítulo 7).fonte
setjmp
/longjmp
só foi especificado quando eles foram usados como um meio de pular para um local dentro de um escopo de outros locais dentro desse mesmo escopo. Depois que o controle sai do escopo ondesetjmp
é executado, qualquer tentativa de usolongjmp
na estrutura criada porsetjmp
resultará em um comportamento indefinido.GOTO A * 40 + B * 200 + 30
. Não é difícil ver como isso foi muito útil e muito perigoso.Hoje, é difícil ver muita coisa sobre a
GOTO
afirmação, porque o pessoal da "programação estruturada" venceu o debate e as linguagens de hoje têm estruturas de fluxo de controle suficientes para evitarGOTO
.Conte o número de
goto
s em um programa C moderno. Agora adicione o número debreak
,continue
ereturn
declarações. Além disso, adicione o número de vezes que você usaif
,else
,while
,switch
oucase
. É sobre quantosGOTO
programas seu programa teria se você estivesse escrevendo em FORTRAN ou BASIC em 1968, quando Dijkstra escreveu sua carta.Faltavam linguagens de programação na época no fluxo de controle. Por exemplo, no Dartmouth BASIC original:
IF
declarações não tinhamELSE
. Se você queria um, tinha que escrever:Mesmo que sua
IF
declaração não precisasse de umaELSE
, ela ainda estava limitada a uma única linha, que geralmente consistia em aGOTO
.Não houve
DO...LOOP
declaração. Para non-FOR
loops, você tinha que terminar o loop com um explícitoGOTO
ouIF...GOTO
voltar ao início.Não houve
SELECT CASE
. Você teve que usarON...GOTO
.Então, você acabou com um monte de
GOTO
s em seu programa. E você não podia depender da restrição deGOTO
s para uma única sub-rotina (porqueGOSUB...RETURN
era um conceito tão fraco de sub-rotinas), para que elasGOTO
pudessem ir a qualquer lugar . Obviamente, isso dificultava o fluxo de controle.É daí
GOTO
que veio o anti- movimento.fonte
420 if (rare_condition) then 3000
//430 and onward: rest of loop and other main-line code
//3000 [code for rare condition]
//3230 goto 430
. Escrever código dessa maneira evita quaisquer ramificações ou saltos no caso comum da linha principal, mas torna as coisas difíceis de seguir. Evitar ramificações no código de montagem pode ser pior, se algumas ramificações estiverem limitadas a, por exemplo, +/- 128 bytes e às vezes não tiverem pares complementares (por exemplo, "cjne" existe, mas não "cje").cjne r0,expected_value,first_comp_springboard
/.../cjne r1,unexpected_value,second_comp_fallthrough
// `ajmp second_comp_target` //first_comp_springboard: ajmp first_comp_target
//second_comp_fallthrough: ...
. Não é um padrão de codificação muito bom, mas quando os ciclos individuais são contados, fazemos essas coisas. É claro que, na década de 1960, esses níveis de otimização eram mais importantes do que hoje, especialmente porque as CPUs modernas geralmente exigem otimizações estranhas, e os sistemas de compilação just-in-time podem aplicar o código de otimização para CPUs que não existiam quando o código em questão foi escrito.Ir para pode fornecer uma espécie de substituto para o tratamento de exceções "real" em certos casos. Considerar:
Obviamente, esse código foi simplificado para ocupar menos espaço; portanto, não fique muito preocupado com os detalhes. Mas considere uma alternativa que eu já vi muitas vezes no código de produção por codificadores com comprimentos absurdos para evitar o uso de goto:
Agora, funcionalmente, esse código faz exatamente a mesma coisa. De fato, o código gerado pelo compilador é quase idêntico. No entanto, no zelo do programador em apaziguar Nogoto (o temido deus da repreensão acadêmica), esse programador quebrou completamente o idioma subjacente que o
while
loop representa e fez um número real na legibilidade do código. Isto não é melhor.Portanto, a moral da história é que, se você se deparar com algo realmente estúpido para evitar usar goto, não o faça.
fonte
break
declarações estarem dentro de uma estrutura de controle deixa claro exatamente o que elas fazem. Com ogoto
exemplo, a pessoa que lê o código precisa procurar o código para encontrar o rótulo, o que, em teoria, poderia estar antes da estrutura de controle. Eu não sou experiente o suficiente com o estilo antigo C para julgar que um é definitivamente melhor que o outro, mas existem compensações de qualquer maneira.break
s estão dentro de um loop deixa claro exatamente que eles saem do loop . Isso não é "exatamente o que eles fazem", pois, na realidade, não há um loop! Nada nele tem chance de se repetir, mas isso não está claro até o fim. O fato de você ter um "loop" que nunca é executado mais de uma vez significa que as estruturas de controle estão sendo abusadas. Com ogoto
exemplo, o programador pode dizergoto error_handler;
. É mais explícito e ainda menos difícil de seguir. (Ctrl + F "error_handler:" para encontrar o alvo Tente fazer isso com "}"..)Donald E. Knuth respondeu a essa pergunta no livro "Literate Programming", 1992 CSLI. Na p. 17, há um ensaio " Programação estruturada com instruções goto " (PDF). Acho que o artigo pode ter sido publicado em outros livros também.
O artigo descreve a sugestão de Dijkstra e descreve as circunstâncias em que isso é válido. Mas ele também fornece vários exemplos de contador (problemas e algoritmos) que não podem ser facilmente reproduzidos usando apenas loops estruturados.
O artigo contém uma descrição completa do problema, histórico, exemplos e exemplos contrários.
fonte
Goto considerado útil.
Comecei a programar em 1975. Para os programadores da década de 1970, as palavras "goto considerado prejudicial" diziam mais ou menos que valia a pena tentar novas linguagens de programação com estruturas de controle modernas. Tentamos os novos idiomas. Nós convertemos rapidamente. Nós nunca voltamos.
Nunca voltamos, mas, se você é mais jovem, nunca esteve lá em primeiro lugar.
Agora, um histórico em linguagens de programação antigas pode não ser muito útil, exceto como um indicador da idade do programador. Não obstante, os programadores mais jovens não têm esse pano de fundo e, portanto, não entendem mais a mensagem que o slogan "considerou prejudicial" transmitido ao público pretendido no momento em que foi apresentado.
Slogans que não se entende não são muito esclarecedores. Provavelmente é melhor esquecer esses slogans. Esses slogans não ajudam.
Esse slogan em particular, no entanto, "Goto considerado prejudicial", ganhou vida própria como morto-vivo.
Goto não pode ser abusado? Resposta: claro, mas e daí? Praticamente todos os elementos de programação podem ser abusados. Os humildes,
bool
por exemplo, são abusados com mais frequência do que alguns de nós gostariam de acreditar.Por outro lado, não me lembro de ter encontrado uma instância única e real de ir a abuso desde 1990.
O maior problema com o goto provavelmente não é técnico, mas social. Os programadores que não sabem muito às vezes parecem sentir que ir embora depreciativo os faz parecer inteligentes. Você pode ter que satisfazer esses programadores de tempos em tempos. Como a vida.
O pior de ir hoje é que ele não é usado o suficiente.
fonte
Atraído por Jay Ballou, adicionando uma resposta, adicionarei meus 0,02 €. Se Bruno Ranschaert ainda não o tivesse feito, eu teria mencionado o artigo "Programação Estruturada com Instruções GOTO" de Knuth.
Uma coisa que não vi discutida é o tipo de código que, embora não seja exatamente comum, foi ensinado nos livros de texto do Fortran. Coisas como a faixa estendida de um loop DO e sub-rotinas de código aberto (lembre-se, isso seria Fortran II ou Fortran IV ou Fortran 66 - não Fortran 77 ou 90). Há pelo menos uma chance de que os detalhes sintáticos sejam inexatos, mas os conceitos devem ser precisos o suficiente. Os trechos em cada caso estão dentro de uma única função.
Observe que o excelente, mas datado (e esgotado) livro ' The Elements of Programming Style, 2nd Edn ' de Kernighan & Plauger inclui alguns exemplos reais de abuso do GOTO da programação de livros didáticos de sua época (final dos anos 70). O material abaixo não é desse livro, no entanto.
Faixa estendida para um loop DO
Uma das razões para tal bobagem foi o bom e velho cartão perfurado. Você pode notar que os rótulos (bem fora de sequência porque esse era o estilo canônico!) Estão na coluna 1 (na verdade, eles precisavam estar nas colunas 1-5) e o código nas colunas 7-72 (a coluna 6 era a continuação coluna do marcador). As colunas 73-80 receberiam um número de sequência e havia máquinas que classificariam os decks de cartões perfurados na ordem dos números de sequência. Se você tivesse o seu programa em cartões sequenciados e precisasse adicionar alguns cartões (linhas) no meio de um loop, seria necessário redesenhar tudo depois dessas linhas extras. No entanto, se você substituir um cartão pelo material GOTO, poderá evitar reequilibrar todos os cartões - basta colocar os novos cartões no final da rotina com novos números de sequência. Considere ser a primeira tentativa de 'computação verde'
Ah, você também pode notar que estou trapaceando e não gritando - o Fortran IV foi escrito em letras maiúsculas normalmente.
Sub-rotina de código aberto
O GOTO entre os rótulos 76 e 54 é uma versão do goto computado. Se a variável i tiver o valor 1, vá para o primeiro rótulo na lista (123); se tiver o valor 2, vá para o segundo e assim por diante. O fragmento de 76 ao goto computado é a sub-rotina de código aberto. Era um pedaço de código executado como uma sub-rotina, mas escrito no corpo de uma função. (O Fortran também tinha funções de instrução - que eram funções incorporadas que cabiam em uma única linha.)
Havia construções piores do que o goto computado - você pode atribuir rótulos a variáveis e, em seguida, usar um goto atribuído. O goto atribuído pelo Google me diz que foi excluído do Fortran 95. Giz um para a revolução da programação estruturada, que pode-se dizer que começou em público com a carta ou artigo "GOTO Considerado Prejudicial" de Dijkstra.
Sem algum conhecimento do tipo de coisas que foram feitas no Fortran (e em outras línguas, a maioria das quais caiu justamente no caminho), é difícil para nós, recém-chegados, entender o escopo do problema com o qual Dijkstra estava lidando. Caramba, eu não comecei a programar até dez anos após a publicação dessa carta (mas tive a infelicidade de programar no Fortran IV por um tempo).
fonte
goto
'in the wild', a pergunta Wanted: Working Bose-Hibbard Sort Algorithm mostra algum código (Algol 60) publicado em 1963. O layout original não se compara aos padrões modernos de codificação. O código esclarecido (recuado) ainda é bastante inescrutável. Asgoto
declarações não fazer torná-lo (muito) difícil entender o que o algoritmo é até.Não há coisas como GOTO consideradas prejudiciais .
GOTO é uma ferramenta e, como todas as ferramentas, pode ser usada e abusada .
No entanto, existem muitas ferramentas no mundo da programação que tendem a ser mais abusadas do que usadas , e o GOTO é uma delas. a declaração WITH de Delphi é outra.
Pessoalmente, eu também não uso no código típico , mas tive o uso estranho de GOTO e WITH que eram justificados, e uma solução alternativa teria mais código.
A melhor solução seria o compilador avisá-lo de que a palavra-chave estava corrompida e você teria que colocar algumas diretivas pragma na declaração para se livrar dos avisos.
É como dizer aos seus filhos para não correrem com tesouras . As tesouras não são ruins, mas talvez algumas delas não sejam a melhor maneira de manter a saúde.
fonte
goto
palavra - chave tenha sido removida do C #, o conceito de "pular aqui" ainda existe em IL. Um loop infinito pode ser facilmente construído sem a palavra-chave goto. Se essa falta de garantia de que o código chamado retornará, na sua opinião, significa "incapaz de raciocinar sobre o código", então eu diria que nunca tivemos essa capacidade.goto
em C # não é um "ir" real no sentido original da palavra. É uma versão muito mais fraca que permite apenas saltar dentro de uma função. O sentido em que estou usando "goto" permite saltar para qualquer lugar do processo. Portanto, embora o C # tenha uma palavra-chave "goto", sem dúvida nunca teve um goto real. Sim, um goto real está disponível no nível IL, da mesma maneira que quando qualquer idioma é compilado no assembly. Mas o programador é protegido disso, incapaz de usá-lo em circunstâncias normais, portanto não conta.Nunca foi, desde que você fosse capaz de pensar por si mesmo.
fonte
Desde que comecei a fazer algumas coisas no kernel do linux, o gotos não me incomoda tanto quanto antes. No começo, fiquei horrorizado ao ver que eles (caras do kernel) adicionaram gotos ao meu código. Desde então, acostumei-me ao uso de gotos, em alguns contextos limitados, e agora os utilizarei ocasionalmente. Normalmente, é necessário ir para o final de uma função para fazer algum tipo de limpeza e resgate, em vez de duplicar a mesma limpeza e resgate em vários locais da função. E tipicamente, não é algo grande o suficiente para passar para outra função - por exemplo, liberar algumas variáveis localmente (k) malloc'ed é um caso típico.
Escrevi código que usava setjmp / longjmp apenas uma vez. Foi em um programa de seqüenciador de bateria MIDI. A reprodução ocorreu em um processo separado de toda a interação do usuário, e o processo de reprodução usou a memória compartilhada com o processo da interface do usuário para obter as informações limitadas necessárias para a reprodução. Quando o usuário quis interromper a reprodução, o processo de reprodução fez apenas um longjmp "do início ao fim", em vez de um desenrolar complicado de onde ele estava sendo executado quando o usuário queria que ele parasse. Funcionou muito bem, era simples e nunca tive problemas ou bugs relacionados a ele nesse caso.
setjmp / longjmp têm seu lugar - mas esse lugar provavelmente não será visitado, mas de vez em quando.
Edit: Acabei de olhar para o código. Na verdade, foi o siglongjmp () que eu usei, não o longjmp (não que seja um grande negócio, mas eu tinha esquecido que o siglongjmp existia).
fonte
Se você está escrevendo uma VM em C, acontece que o uso de gotos computados (gcc) é o seguinte:
funciona muito mais rápido que o comutador convencional dentro de um loop.
fonte
&&op_inc
certamente não compila, porque (à esquerda)&
espera um lvalue, mas (à direita)&
produz um rvalue.Porque
goto
pode ser usado para confundir metaprogramaçãoGoto
é uma expressão de controle de alto e baixo nível e, como resultado, simplesmente não possui um padrão de design apropriado para a maioria dos problemas.É de baixo nível no sentido de que um goto é uma operação primitiva que implementa algo maior como
while
ouforeach
ou algo assim.É de alto nível, no sentido de que, quando usado de certas maneiras, leva o código que é executado em uma sequência clara, de forma ininterrupta, exceto para loops estruturados, e o transforma em pedaços de lógica que são, com
goto
s suficientes , - saco de lógica sendo dinamicamente remontado.Portanto, existe um lado prosaico e um lado maligno
goto
.O lado prosaico é que um goto apontando para cima pode implementar um loop perfeitamente razoável e um goto apontando para baixo pode fazer um
break
ou perfeitamente razoávelreturn
. É claro que um realwhile
,break
oureturn
seria muito mais legível, pois o pobre humano não precisaria simular o efeito dogoto
para obter uma visão geral. Então, uma má ideia em geral.O lado mau envolve uma rotina que não usa goto por um tempo, pausa ou retorno, mas usa-a para o que se chama lógica de espaguete . Nesse caso, o desenvolvedor goto-feliz está construindo pedaços de código a partir de um labirinto de goto, e a única maneira de entendê-lo é simulá-lo mentalmente como um todo, uma tarefa terrivelmente cansativa quando há muitos goto. Quero dizer, imagine o problema de avaliar o código onde
else
não é precisamente o inverso doif
, ondeif
s aninhados podem permitir algumas coisas que foram rejeitadas pelo externoif
, etc.Finalmente, para realmente cobrir o assunto, devemos observar que essencialmente todas as línguas antigas, exceto Algol, inicialmente fizeram apenas declarações individuais sujeitas às suas versões de
if-then-else
. Portanto, a única maneira de fazer um bloco condicional eragoto
contorná-lo usando uma condicional inversa. Insano, eu sei, mas eu li algumas especificações antigas. Lembre-se de que os primeiros computadores foram programados em código de máquina binário, portanto, suponho que qualquer tipo de HLL seja um salva-vidas; Eu acho que eles não eram muito exigentes sobre exatamente quais recursos da HLL eles tinham.Tendo dito tudo o que costumava colocar
goto
em cada programa que escrevi "apenas para irritar os puristas" .fonte
Negar o uso da declaração GOTO aos programadores é como dizer a um carpinteiro que não use um martelo, pois pode danificar a parede enquanto ele está martelando um prego. Um verdadeiro programador sabe como e quando usar um GOTO. Eu segui atrás de alguns desses chamados 'Programas Estruturados'. Vejo esse código Horrid apenas para evitar o uso de um GOTO, que eu poderia atirar no programador. Ok, em defesa do outro lado, eu também vi códigos de espaguete de verdade, e esses programadores também devem ser atingidos.
Aqui está apenas um pequeno exemplo de código que encontrei.
-----------------------OU----------------------
fonte
goto
- e sabe o porquê . Evitando uma construção de linguagem tabu porque o $ programming_guru disse isso, essa é a própria definição de programação de cultos de carga."Neste link http://kerneltrap.org/node/553/2131 "
Ironicamente, a eliminação do goto introduziu um bug: a chamada do spinlock foi omitida.
fonte
O artigo original deve ser considerado como "GOTO Incondicional Considerado Prejudicial". Ele defendia, em particular, uma forma de programação baseada em construções condicionais (
if
) e iterativas (while
), em vez do teste e salto comum ao código inicial.goto
ainda é útil em alguns idiomas ou circunstâncias, onde não existe uma estrutura de controle apropriada.fonte
O único lugar em que concordo que Goto poderia ser usado é quando você precisa lidar com erros, e cada ponto em que ocorre um erro requer um tratamento especial.
Por exemplo, se você está pegando recursos e usando semáforos ou mutexes, precisa pegá-los em ordem e sempre deve liberá-los da maneira oposta.
Algum código requer um padrão muito estranho de capturar esses recursos, e você não pode simplesmente escrever uma estrutura de controle de fácil manutenção e compreensão para lidar corretamente com a captura e a liberação desses recursos para evitar conflitos.
É sempre possível fazer o que é certo sem ir, mas neste caso e em alguns outros, o Ir é na verdade a melhor solução, principalmente para facilitar a leitura e a manutenção.
-Adão
fonte
Um uso moderno do GOTO é pelo compilador C # para criar máquinas de estado para enumeradores definidos pelo retorno de rendimento.
GOTO é algo que deve ser usado por compiladores e não por programadores.
fonte
goto
. Onde podemos usargoto
em uma máquina de estado codificada manualmente para implementar um enumerador, podemos apenas usá-loyield
.Até que C e C ++ (entre outros culpados) rotulem quebras e continuem, goto continuará tendo um papel.
fonte
Se o próprio GOTO fosse ruim, os compiladores seriam ruins, porque eles geram JMPs. Se pular em um bloco de código, especialmente após um ponteiro, fosse inerentemente mau, a instrução RETurn seria má. Pelo contrário, o mal está em potencial para abuso.
Às vezes, eu tive que escrever aplicativos que precisavam acompanhar vários objetos em que cada objeto tinha que seguir uma intrincada sequência de estados em resposta a eventos, mas a coisa toda era definitivamente um thread único. Uma sequência típica de estados, se representada no pseudo-código, seria:
Tenho certeza de que isso não é novo, mas a maneira como lidei com C (++) foi definir algumas macros:
Então (assumindo que o estado é inicialmente 0), a máquina de estados estruturados acima se transforma no código estruturado:
Com uma variação disso, pode haver CALL e RETURN, para que algumas máquinas de estado possam agir como sub-rotinas de outras máquinas de estado.
Isso é incomum? Sim. É preciso algum aprendizado por parte do mantenedor? Sim. Esse aprendizado vale a pena? Acho que sim. Isso poderia ser feito sem os GOTOs que pulam em blocos? Não.
fonte
Eu o evito, pois um colega / gerente indubitavelmente questiona seu uso em uma revisão de código ou quando se depara com ela. Embora eu ache que ele tenha usos (o caso de manipulação de erros, por exemplo) - você encontrará algum outro desenvolvedor que terá algum tipo de problema com ele.
Não vale a pena.
fonte
Na verdade, eu me vi forçado a usar um goto, porque eu literalmente não conseguia pensar em uma maneira melhor (mais rápida) de escrever esse código:
Eu tinha um objeto complexo e precisava fazer alguma operação nele. Se o objeto estivesse em um estado, eu poderia fazer uma versão rápida da operação, caso contrário, teria que fazer uma versão lenta da operação. O fato é que, em alguns casos, no meio da operação lenta, era possível perceber que isso poderia ter sido feito com a operação rápida.
Isso estava em uma parte crítica da velocidade do código da interface do usuário em tempo real, então sinceramente acho que um GOTO foi justificado aqui.
Hugo
fonte
Quase todas as situações em que um goto pode ser usado, você pode fazer o mesmo usando outras construções. Goto é usado pelo compilador de qualquer maneira.
Eu pessoalmente nunca o uso explicitamente, nunca preciso.
fonte
Uma coisa que eu não vi em nenhuma das respostas aqui é que uma solução 'goto' geralmente é mais eficiente do que uma das soluções de programação estruturada mencionadas com frequência.
Considere o caso de muitos aninhados loops, onde usar 'goto' em vez de
if(breakVariable)
várias seções é obviamente mais eficiente. A solução "Coloque seus loops em uma função e use return" é muitas vezes totalmente irracional. No caso provável de os loops estarem usando variáveis locais, agora você precisa passá-los por todos os parâmetros de função, potencialmente manipulando cargas de dores de cabeça extras que surgem disso.Agora considere o caso de limpeza, que eu já usei com bastante frequência, e é tão comum que provavelmente fui responsável pela estrutura try {} catch {} que não está disponível em muitos idiomas. O número de verificações e variáveis extras necessárias para realizar a mesma coisa é muito pior do que as uma ou duas instruções para dar o salto e, novamente, a solução de função adicional não é uma solução. Você não pode me dizer que é mais gerenciável ou mais legível.
Agora, o espaço do código, o uso da pilha e o tempo de execução podem não ser suficientes em muitas situações para muitos programadores, mas quando você está em um ambiente incorporado com apenas 2 KB de espaço para trabalhar, 50 bytes de instruções extras para evitar uma definição clara. 'goto' é simplesmente risível, e essa não é uma situação tão rara quanto muitos programadores de alto nível acreditam.
A afirmação de que "ir é prejudicial" foi muito útil para avançar para a programação estruturada, mesmo que sempre tenha sido uma generalização excessiva. Neste ponto, todos nós já ouvimos o suficiente para ser cauteloso em usá-lo (como deveríamos). Quando é obviamente a ferramenta certa para o trabalho, não precisamos ter medo disso.
fonte
Você pode usá-lo para interromper um loop profundamente aninhado, mas na maioria das vezes seu código pode ser refatorado para ficar mais limpo sem loops profundamente aninhados.
fonte