it-swarm-es.com

¿Vale la pena usar goto?

goto es casi universalmente desaconsejado. ¿Vale la pena usar esta declaración?

30
Casebash

Esto se ha discutido varias veces en Stack Overflow, y Chris Gillum resumió los posibles usos de goto :

Salir limpiamente de una función

A menudo, en una función, puede asignar recursos y debe 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, todos los "puntos de salida" de la función irían a la etiqueta de limpieza. De esta manera, no tiene que 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 bucles, un goto puede hacer esto mucho más limpio y simple que las declaraciones de interrupción y las comprobaciones de if.

Mejoras de rendimiento de bajo nivel

Esto solo es válido en el código crítico, pero las instrucciones goto se ejecutan muy rápidamente y pueden darle un impulso cuando se mueve a través de una función. Sin embargo, esta es una espada de doble filo, porque un compilador generalmente no puede optimizar el código que contiene gotos.

Yo diría, como muchos otros argumentan, que en todos estos casos, el uso de goto se usa como un medio para salir de una esquina en la que uno se codificó, y generalmente es un síntoma de código eso podría ser refactorizado.

51
user8

Las construcciones de flujo de control de nivel superior tienden a corresponder a conceptos en el dominio del problema. Un if/else es una decisión basada en alguna condición. Un bucle dice que realice alguna acción repetidamente. Incluso una declaración de ruptura dice "estábamos haciendo esto repetidamente, pero ahora tenemos que parar".

Una declaración goto, por otro lado, tiende a corresponder a un concepto en el programa en ejecución, no en el dominio del problema. Dice continuar la ejecución en un punto específico en el programa . Alguien que lea el código tiene que inferir lo que eso significa con respecto al dominio del problema.

Por supuesto, todas las construcciones de nivel superior se pueden definir en términos de gotos y ramas condicionales simples. Eso no quiere decir que sean simplemente disfraces disfrazados. Piense en ellos como restringidos gotos - y son las restricciones las que los hacen útiles. Una declaración de interrupción se implementa como un salto al final del ciclo de cierre, pero es mejor pensar que opera en el ciclo como un todo.

En igualdad de condiciones, el código cuya estructura refleja la del dominio del problema tiende a ser más fácil de leer y mantener.

No hay casos en los que sea absolutamente necesaria una declaración goto (hay n teorema para ese efecto), pero hay casos en los que puede ser la solución menos mala. Esos casos varían de un idioma a otro, dependiendo de qué construcciones de nivel superior admite el idioma.

En C, por ejemplo, creo que hay tres escenarios básicos donde un goto es apropiado.

  1. Salir de un bucle anidado. Esto sería innecesario si el idioma tuviera una declaración de rotura etiquetada.
  2. Rescate de un tramo de código (generalmente un cuerpo de función) en caso de error u otro evento inesperado. Esto sería innecesario si el idioma tuviera excepciones.
  3. Implementación de una máquina explícita de estados finitos. En este caso (y, creo, solo en este caso) un goto corresponde directamente a un concepto en el dominio del problema, pasando de un estado a otro estado específico, donde el estado actual está representado por qué bloque de código se está ejecutando actualmente .

Por otro lado, una máquina explícita de estados finitos también se puede implementar con una declaración de cambio dentro de un bucle. Esto tiene la ventaja de que cada estado comienza en el mismo lugar en el código, lo que puede ser útil para la depuración, por ejemplo.

El uso principal de un goto en un lenguaje razonablemente moderno (uno que admite if/else y bucles) es simular una construcción de flujo de control que falta en el lenguaje.

46
Keith Thompson

Seguramente depende del lenguaje de programación. La razón principal por la que goto ha sido controvertida es por sus efectos nocivos que surgen cuando el compilador le permite usarlo demasiado liberalmente. Pueden surgir problemas, por ejemplo, si le permite usar goto de tal manera que ahora puede acceder a una variable no inicializada, o peor, para saltar a otro método y meterse con la pila de llamadas. Debería ser responsabilidad del compilador rechazar el flujo de control sin sentido.

Java ha intentado "resolver" este problema al no permitir goto por completo. Sin embargo, Java le permite usar return dentro de un bloque finally y, por lo tanto, invoca inadvertidamente una excepción. El mismo problema sigue ahí: el compilador está no está haciendo su trabajo. Eliminar goto del idioma no lo ha solucionado.

En C #, goto es tan seguro como break, continue, try/catch/finally y return. No le permite usar variables no inicializadas, no le permite saltar de un bloque finalmente, etc. El compilador se quejará. Esto se debe a que resuelve el problema real, que es como dije flujo de control sin sentido. goto no cancela mágicamente el análisis de asignación definitiva y otras comprobaciones razonables del compilador.

11
Timwi

Si. Cuando sus bucles están anidados en varios niveles de profundidad, goto es la forma solo de salir con elegancia de un bucle interno. La otra opción es establecer una bandera y salir de cada ciclo si esa bandera cumple una condición. Esto es realmente feo y bastante propenso a errores. En estos casos, goto es simplemente mejor.

Por supuesto, la declaración break de Java hace lo mismo, pero sin permitirle saltar a un punto arbitrario en el código, lo que resuelve el problema perfectamente sin permitir las cosas que hacen que goto sea malo.

9
Chinmay Kanchi

La mayor parte del desánimo proviene de una especie de "religión" creada por Dios Djikstra que fue convincente a principios de los años 60 sobre su poder indiscriminado para:

  • saltar a cualquier parte del bloque de código
    • función no ejecutada desde el principio
    • bucles no ejecutados desde el principio
    • inicialización de variable omitida
  • salte de cualquier bloque de código sin ninguna posible limpieza.

Esto no tiene nada más que ver con la declaración goto de los lenguajes modernos, cuya existencia se debe simplemente a apoyar la creación de estructuras de código distintas de las proporcionadas por el lenguaje.

En particular, el primer punto principal anterior ya está permitido y el segundo se limpia (si goto fuera de un bloque, la pila se desenrolla correctamente y se llaman todos los destructores adecuados)

Puede consultar esta respuesta para tener una idea de cómo incluso el código que no usa goto puede ser ilegible. El problema no es ir a sí mismo, sino su mal uso.

Puedo escribir un programa completo sin usar if, solo for. Por supuesto, no será fácil de leer, se verá torpe e innecesariamente complicado.

Pero el problema no es for. Soy yo.

Cosas como break, continue, throw, bool needed=true; while(needed) {...}, etc. están notando más que masquerade goto para escapar de las cimitarras de los fanáticos de Djikstrarian, que -50 años después de la invención de las lenguas modernas- todavía quieren a sus prisioneros. Se olvidaron de lo que Djikstra estaba hablando, solo recuerdan el título de su nota (GOTO lo consideró dañino, y ni siquiera era su único título: fue cambiado por el editor) y culpan y golpean, golpean y culpan a cada constructor que tiene esos 4 carta colocada en secuencia.

Es 2011: es hora de entender que goto tiene que hacer frente a la declaración GOTO por la que Djikstra fue convincente.

7

El goto extraño aquí o allá, siempre que sea local para una función, rara vez perjudica significativamente la legibilidad. A menudo lo beneficia al llamar la atención sobre el hecho de que hay algo inusual en este código que requiere el uso de una estructura de control poco común.

Si los gotos (locales) están dañando significativamente la legibilidad, generalmente es una señal de que la función que contiene el goto se ha vuelto demasiado compleja.

El último goto que puse en un fragmento de código C fue construir un par de bucles entrelazados. No se ajusta a la definición normal de uso de goto "aceptable", pero como resultado la función terminó siendo significativamente más pequeña y clara. Para evitar el goto habría requerido una violación particularmente desordenada de DRY.

4
blucz

Creo que todo este problema ha sido un caso de ladrar al árbol equivocado.

GOTO como tal no me parece problemático, sino que a menudo es un síntoma de un pecado real: el código de espagueti.

Si el GOTO causa un cruce importante de las líneas de control de flujo, entonces es malo, punto. Si no cruza las líneas de control de flujo, es inofensivo. En la zona gris en el medio tenemos cosas como rescates en bucle, todavía hay algunos idiomas que no han agregado construcciones que cubran todos los casos grises legítimos.

El único caso en el que me he encontrado usándolo en muchos años es el caso del bucle donde el punto de decisión está en el medio del bucle. Te quedan códigos duplicados, una bandera o un GOTO. La solución GOTO me parece la mejor de las tres. No hay cruce de líneas de control de flujo aquí, es inofensivo.

3
Loren Pechtel

Sí, el goto se puede utilizar para beneficiar la experiencia del desarrollador: http://adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/

Sin embargo, al igual que con cualquier herramienta poderosa (punteros, herencia múltiple, etc.), uno debe ser disciplinado al usarla. El ejemplo proporcionado en el enlace usa PHP, que restringe el uso de la construcción goto a la misma función/método y deshabilita la capacidad de saltar a un nuevo bloque de control (por ejemplo, bucle, instrucción de cambio, etc.)

1
AdamJonR

Depende del idioma. Todavía se usa ampliamente en la programación de Cobol, por ejemplo. También he trabajado en un dispositivo Barionet 50, cuyo lenguaje de programación de firmware es un dialecto BASIC temprano que, por supuesto, requiere que uses Goto.

1
user16764

Yo diría que no. Si encuentra la necesidad de usar GOTO, apuesto a que es necesario rediseñar el código.

0
Walter