¿Existen casos de uso legítimos para "goto" en un lenguaje que admita bucles y funciones?

Resuelto Landon asked hace 16 años • 25 respuestas

Durante mucho tiempo he tenido la impresión de que, gotosi es posible, nunca debería usarse.

Sin embargo, mientras examinaba libavcodec (que está escrito en C) el otro día, me sorprendió notar sus múltiples usos.

¿Alguna vez es ventajoso usarlo gotoen un lenguaje que admita bucles y funciones? Si es así, ¿por qué? Proporcione un ejemplo concreto que justifique claramente el uso de un archivo goto.

Landon avatar Aug 24 '08 01:08 Landon
Aceptado

Todos los que están en contra gotocitan, directa o indirectamente, el artículo GoTo Considered Harmful de Edsger Dijkstra para fundamentar su posición. Lástima que el artículo de Dijkstra prácticamente no tiene nada que ver con la forma en que gotose usan las declaraciones hoy en día y, por lo tanto, lo que dice el artículo tiene poca o ninguna aplicabilidad en la escena de la programación moderna. El gotomeme menos ahora raya en una religión, hasta en sus escrituras dictadas desde lo alto, sus sumos sacerdotes y el rechazo (o algo peor) de los percibidos como herejes.

Pongamos en contexto el artículo de Dijkstra para arrojar un poco de luz sobre el tema.

Cuando Dijkstra escribió su artículo, los lenguajes populares de la época eran procedimentales no estructurados como BASIC, FORTRAN (los dialectos anteriores) y varios lenguajes ensambladores. Era bastante común que las personas que usaban lenguajes de nivel superior saltaran sobre su base de código en hilos de ejecución retorcidos y retorcidos que dieron lugar al término "código espagueti". Puedes ver esto saltando al clásico juego Trek escrito por Mike Mayfield y tratando de descubrir cómo funcionan las cosas. Tómate unos momentos para revisar eso.

ESTE es "el uso desenfrenado de la frase ir a" contra el cual Dijkstra criticaba en su artículo de 1968. ESTE es el entorno en el que vivió y que lo llevó a escribir ese artículo. La capacidad de saltar a cualquier lugar que desee en su código en cualquier punto que desee era lo que criticaba y exigía que se detuviera. Comparar eso con los poderes anémicos de gotoC u otros lenguajes más modernos es simplemente ridículo.

Ya puedo escuchar los cánticos elevados de los cultistas mientras se enfrentan al hereje. "Pero", corearán, "puedes hacer que el código sea muy difícil de leer en gotoC". ¿Oh sí? gotoTambién puedes hacer que el código sea muy difícil de leer . Como éste:

#define _ -F<00||--F-OO--;
int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_
            _-_-_-_
}

No está gotoa la vista, por lo que debe ser fácil de leer, ¿verdad? O qué tal este:

a[900];     b;c;d=1     ;e=1;f;     g;h;O;      main(k,
l)char*     *l;{g=      atoi(*      ++l);       for(k=
0;k*k<      g;b=k       ++>>1)      ;for(h=     0;h*h<=
g;++h);     --h;c=(     (h+=g>h     *(h+1))     -1)>>1;
while(d     <=g){       ++O;for     (f=0;f<     O&&d<=g
;++f)a[     b<<5|c]     =d++,b+=    e;for(      f=0;f<O
&&d<=g;     ++f)a[b     <<5|c]=     d++,c+=     e;e= -e
;}for(c     =0;c<h;     ++c){       for(b=0     ;b<k;++
b){if(b     <k/2)a[     b<<5|c]     ^=a[(k      -(b+1))
<<5|c]^=    a[b<<5      |c]^=a[     (k-(b+1     ))<<5|c]
;printf(    a[b<<5|c    ]?"%-4d"    :"    "     ,a[b<<5
|c]);}      putchar(    '\n');}}    /*Mike      Laman*/

Allí tampoco goto. Por tanto, debe ser legible.

¿Cuál es mi punto con estos ejemplos? No son las características del lenguaje las que hacen que el código sea ilegible e imposible de mantener. No es la sintaxis la que lo hace. Son los malos programadores los que causan esto. Y los malos programadores, como puede ver en el elemento anterior, pueden hacer que cualquier característica del lenguaje sea ilegible e inutilizable. Como los forbucles de ahí arriba. (Puedes verlos, ¿verdad?)

Ahora bien, para ser justos, es más fácil abusar de algunas construcciones del lenguaje que de otras. Sin embargo, si eres un programador de C, observaría mucho más de cerca aproximadamente el 50% de los usos de #definemucho antes de emprender una cruzada contra goto.

Entonces, para aquellos que se han molestado en leer hasta aquí, hay varios puntos clave a tener en cuenta.

  1. El artículo de Dijkstra sobre gotodeclaraciones fue escrito para un entorno de programación donde gotoera mucho más dañino que en la mayoría de los lenguajes modernos que no son ensambladores.
  2. Desechar automáticamente todos los usos de gotodebido a esto es tan racional como decir "Traté de divertirme una vez pero no me gustó, así que ahora estoy en contra".
  3. Hay usos legítimos de las gotodeclaraciones modernas (anémicas) en el código que no pueden ser reemplazadas adecuadamente por otras construcciones.
  4. Por supuesto, existen usos ilegítimos de las mismas declaraciones.
  5. También existen usos ilegítimos de las declaraciones de control modernas, como la " " abominación en la que se rompe godoun bucle siempre falso en lugar de un . Estos suelen ser peores que el uso sensato de .dobreakgotogoto
JUST MY correct OPINION avatar May 11 '2010 09:05 JUST MY correct OPINION

Hay algunas razones para usar la declaración "goto" que yo sepa (algunos ya han hablado de esto):

Salir limpiamente de una función

A menudo, en una función, puede asignar recursos y necesitar salir en varios lugares. Los programadores pueden simplificar su código colocando el código de limpieza de recursos al final de la función, y todos los "puntos de salida" de la función irán a la etiqueta de limpieza. De esta manera, no es necesario escribir código de limpieza en cada "punto de salida" de la función.

Salir de bucles anidados

Si está en un bucle anidado y necesita salir de todos los bucles, un goto puede hacer que esto sea mucho más limpio y simple que las declaraciones break y las comprobaciones if.

Mejoras de rendimiento de bajo nivel

Esto solo es válido en código de rendimiento crítico, pero las declaraciones goto se ejecutan muy rápidamente y pueden darle un impulso al moverse por una función. Sin embargo, esto es un arma de doble filo, porque un compilador normalmente no puede optimizar el código que contiene gotos.

Tenga en cuenta que en todos estos ejemplos, los gotos están restringidos al alcance de una única función.

Chris Gillum avatar Aug 23 '2008 18:08 Chris Gillum

Obedecer ciegamente las mejores prácticas no es una buena práctica. La idea de evitar gotodeclaraciones como forma principal de control de flujo es evitar producir código espagueti ilegible. Si se usan con moderación y en los lugares correctos, a veces pueden ser la forma más sencilla y clara de expresar una idea. Walter Bright, creador del compilador Zortech C++ y del lenguaje de programación D, los utiliza con frecuencia, pero con prudencia. Incluso con las gotodeclaraciones, su código sigue siendo perfectamente legible.

En pocas palabras: evitar gotopor evitar gotono tiene sentido. Lo que realmente quieres evitar es producir código ilegible. Si su gotocódigo cargado es legible, entonces no tiene nada de malo.

dsimcha avatar Feb 02 '2010 19:02 dsimcha

Bueno, hay una cosa que siempre es peor que goto's; uso extraño de otros operadores de flujo de programa para evitar un goto:

Ejemplos:

    // 1
    try{
      ...
      throw NoErrorException;
      ...
    } catch (const NoErrorException& noe){
      // This is the worst
    } 


    // 2
    do {
      ...break; 
      ...break;
    } while (false);


    // 3
    for(int i = 0;...) { 
      bool restartOuter = false;
      for (int j = 0;...) {
        if (...)
          restartOuter = true;
      if (restartOuter) {
        i = -1;
      }
    }

etc
etc
Viktor Sehr avatar May 11 '2010 09:05 Viktor Sehr

Dado que gotodificulta el razonamiento sobre el flujo del programa 1 (también conocido como “código espagueti”), gotogeneralmente solo se usa para compensar características faltantes: el uso de gotopuede ser aceptable, pero solo si el lenguaje no ofrece una variante más estructurada para obtener el mismo objetivo. Tomemos el ejemplo de la duda:

La regla que usamos con goto es que goto está bien para saltar hacia un único punto de limpieza de salida en una función.

Esto es cierto, pero solo si el lenguaje no permite el manejo estructurado de excepciones con código de limpieza (como RAII o finally), que hace mejor el mismo trabajo (ya que está diseñado especialmente para hacerlo), o cuando hay una buena razón para no hacerlo. emplear un manejo estructurado de excepciones (pero nunca tendrá este caso excepto en un nivel muy bajo).

En la mayoría de los demás idiomas, el único uso aceptable gotoes salir de bucles anidados. E incluso allí, casi siempre es mejor levantar el bucle exterior con un método propio y utilizarlo returnen su lugar.

Aparte de eso, gotoes una señal de que no se ha pensado lo suficiente en ese fragmento de código en particular.


1 Los lenguajes modernos que admiten gotoimplementan algunas restricciones (por ejemplo, gotono pueden entrar o salir de funciones), pero el problema sigue siendo fundamentalmente el mismo.

Por cierto, lo mismo también se aplica a otras características del lenguaje, sobre todo a las excepciones. Y normalmente existen reglas estrictas para usar estas funciones solo cuando se indique, como la regla de no usar excepciones para controlar el flujo de programas no excepcionales.

Konrad Rudolph avatar Aug 23 '2008 18:08 Konrad Rudolph