Recentemente, o Fabiano Vasconcelos abriu uma discussão no Grupo de Usuários de C e C++:
Acredito que praticamente todo programador treinado nos últimos vinte anos aprendeu a programar com if e while. Essas são as estruturas básicas de programas e aparecem rapidamente nos manuais e nos cursos de programação. Toda linguagem de programação moderna tem if e while, e variantes como switch, for etc.
Essas coisas são chamadas estruturas de controle porque fazem exatamente isso: controlam a execução do programa, às vezes indo para uma sequência de sentenças, às vezes indo para outra, de acordo com testes explícitos. Arranjar um programa com sequências de sentenças, if e while é fazer programação estruturada.
Agora, a não ser que algum curso maravilhoso e desconhecido por mim tenha história da programação no seu currículo, este programador provavelmente não percebe que if e while nem sempre existiram e que a programação estruturada foi inventada mais ou menos na década de 70.
Durante a discussão no grupo de desenvolvimento do Linux, Scott Robert Ladd disse o seguinte:
Considere este fragmento:
char * i = input;
while (*i != '\0')
if (*i == SPECIAL) goto exit;
else ++i;
:exit
return i;
Este fragmento _não_ é o objeto da objeção ao uso de goto. Este fragmento exibe honrada programação estruturada. goto está ali como bem poderia estar break. Tanto faz.
Agora, observe este fragmento:
char * i = input;
:loop
if (*i == '\0') goto exit;
if (*i == SPECIAL) goto exit;
++i;
goto loop;
:exit
return i;
Isto é o que você deve evitar.
O objetivo do combate ao goto era combater a programação não-estruturada, e esse combate foi vencido com a introdução das linguagens estruturadas. Tais linguagens levam o programador naturalmente ao caminho certo e proíbem os maiores absurdos.
Existem linguagens em que o último fragmento acima era _a única alternativa_. (Ou coisa pior.)
Em retrospectiva, sabemos que a programação não-estruturada dominante na época causava um modo de pensar não-estruturado sobre os programas, de modo que o "spagetthi code" clássico era um único fluxo de instruções com gotos arbitrários para cima e para baixo, algo muito pior que o último fragmento acima, o tipo de código que eu não saberia construir artificialmente.
Se você conhece e pratica a programação de acordo com os bons princípios da programação estruturada, não precisa temer o goto. Existem diversas situações excepcionais às quais as estruturas de controle do C não se adequam perfeitamente; aquela que me ocorre com mais frequência são switches dentro de for quando é preciso terminar o for dentro de um case.
for (char * i = input; *i != '\0'; ++i)
switch (state)
{
case FOO:
/* many things */
break;
case BAR:
if (*i == SPECIAL) goto exit;
/* many things */
break;
}
exit:
Sempre existe uma maneira de remover o goto; nem sempre essa maneira é desejável. O goto acima, cujo label está exatamente na saída do laço, me parece uma parte bastante adequada da estrutura de controle. Java, que não possui goto, permite dizer "break exit", com exatamente o mesmo significado.
Durante a discussão no grupo de desenvolvimento do Linux, Robert Love disse o seguinte sobre a substituição do goto por outras estruturas:
if (error) goto out_a;
do B
if (error) goto out_b;
do C
if (error) goto out_c;
goto out;
out_c:
undo C
out_b:
undo B:
out_a:
undo A
out:
return ret;
De cara eu vi algo aqui um pouco estranho, se que o amigo Márcio me permite comentar: que muitos programadores, inclusive eu (se que posso ser rotulado como programador) foram instruídos com o princípio de NUNCA usar o goto, por ser considerado um mau estilo de programação.Durante a discussão, o Eduardo Vieira puxou um artigo da KernelTrap sobre uma discussão similar ocorrida no grupo de desenvolvimento do Linux, onde Robert Wilken disse o seguinte:
In general, if you can structure your code properly, you should never need a goto, and if you don't need a goto you shouldn't use it. It's just "common sense" as I've always been taught. Unless you're intentionally trying to write code that's harder for others to read.É preciso colocar a máxima "goto considered harmful" na perspectiva histórica adequada.
Acredito que praticamente todo programador treinado nos últimos vinte anos aprendeu a programar com if e while. Essas são as estruturas básicas de programas e aparecem rapidamente nos manuais e nos cursos de programação. Toda linguagem de programação moderna tem if e while, e variantes como switch, for etc.
Essas coisas são chamadas estruturas de controle porque fazem exatamente isso: controlam a execução do programa, às vezes indo para uma sequência de sentenças, às vezes indo para outra, de acordo com testes explícitos. Arranjar um programa com sequências de sentenças, if e while é fazer programação estruturada.
Agora, a não ser que algum curso maravilhoso e desconhecido por mim tenha história da programação no seu currículo, este programador provavelmente não percebe que if e while nem sempre existiram e que a programação estruturada foi inventada mais ou menos na década de 70.
Durante a discussão no grupo de desenvolvimento do Linux, Scott Robert Ladd disse o seguinte:
Your attitude against "goto" is perhaps based upon an excellent but dated article, "Goto Considered Harmful", written by Edsger W. Dijkstra, and published by the ACM in 1968. (A recent reprint can be found at http://www.acm.org/classics/oct95/.) As you can tell from the date, this article predates modern programming languages and idioms; it comes from a time when Fortran ruled, and before Fortran 77 provided significant tools for avoiding spaghetti code.e mais o seguinte:
Used over short distances with well-documented labels, a "goto" can be more effective, faster, and cleaner than a series of complex flags or other constructs. The "goto" may also be safer and more intuitive than the alternative. A "break" is a goto; a "continue" is a "goto" -- these are statements that move the point of execution explicitly.Dijkstra, e outros, iniciaram a pequena revolta estruturada e assim ocorreu que diversas linguagens de programação introduziram novidades como if e while. Mas como é possível programar sem if e while?
Considere este fragmento:
char * i = input;
while (*i != '\0')
if (*i == SPECIAL) goto exit;
else ++i;
:exit
return i;
Este fragmento _não_ é o objeto da objeção ao uso de goto. Este fragmento exibe honrada programação estruturada. goto está ali como bem poderia estar break. Tanto faz.
Agora, observe este fragmento:
char * i = input;
:loop
if (*i == '\0') goto exit;
if (*i == SPECIAL) goto exit;
++i;
goto loop;
:exit
return i;
Isto é o que você deve evitar.
O objetivo do combate ao goto era combater a programação não-estruturada, e esse combate foi vencido com a introdução das linguagens estruturadas. Tais linguagens levam o programador naturalmente ao caminho certo e proíbem os maiores absurdos.
Existem linguagens em que o último fragmento acima era _a única alternativa_. (Ou coisa pior.)
Em retrospectiva, sabemos que a programação não-estruturada dominante na época causava um modo de pensar não-estruturado sobre os programas, de modo que o "spagetthi code" clássico era um único fluxo de instruções com gotos arbitrários para cima e para baixo, algo muito pior que o último fragmento acima, o tipo de código que eu não saberia construir artificialmente.
Se você conhece e pratica a programação de acordo com os bons princípios da programação estruturada, não precisa temer o goto. Existem diversas situações excepcionais às quais as estruturas de controle do C não se adequam perfeitamente; aquela que me ocorre com mais frequência são switches dentro de for quando é preciso terminar o for dentro de um case.
for (char * i = input; *i != '\0'; ++i)
switch (state)
{
case FOO:
/* many things */
break;
case BAR:
if (*i == SPECIAL) goto exit;
/* many things */
break;
}
exit:
Sempre existe uma maneira de remover o goto; nem sempre essa maneira é desejável. O goto acima, cujo label está exatamente na saída do laço, me parece uma parte bastante adequada da estrutura de controle. Java, que não possui goto, permite dizer "break exit", com exatamente o mesmo significado.
Durante a discussão no grupo de desenvolvimento do Linux, Robert Love disse o seguinte sobre a substituição do goto por outras estruturas:
As a final argument, it does not let us cleanly do the usual stack-esque wind and unwind, i.e.do A
if (error) goto out_a;
do B
if (error) goto out_b;
do C
if (error) goto out_c;
goto out;
out_c:
undo C
out_b:
undo B:
out_a:
undo A
out:
return ret;
Now stop this.
Comentários
Postar um comentário