goto
está casi universalmente desanimado. ¿Vale la pena usar esta declaración?
goto
programming-practices
Casebash
fuente
fuente
goto
es lo que finalmente hace la CPU, pero no funciona bien con lo que los humanos necesitan comprender y abstraer debido a que no hay una marca en el extremo objetivo. Compare con IntercalCOMEFROM
.goto
no es obligatorio. Es la forma más racional de implementarlos en los lenguajes imperativos, ya que es lo más parecido a la semántica de la transición de estado. Y su destino puede estar bastante lejos de la fuente, no obstaculizará la legibilidad. Mi ejemplo favorito de dicho código es la implementación de DE Knuth del juego Adventure.Respuestas:
Esto se ha discutido varias veces en Stack Overflow, y Chris Gillum resumió los posibles usos de
goto
:Yo diría, como muchos otros argumentan, que en todos estos casos, el uso de
goto
se utiliza como un medio para salir de una esquina en el que uno se codificó, y generalmente es un síntoma de código que podría ser refactorizado.fuente
finally
bloques en los idiomas modernos, y el segundo se resuelve con la etiquetabreak
s. Sin embargo, si está atascado con C,goto
es prácticamente la única forma de resolver estos problemas con elegancia.finally
solo es válido en esas condiciones. Hay situaciones muy raras pero válidas en las que un goto es el camino a seguir.break 3
obreak myLabel
ygoto myLabel
. Oh, eso es justo la palabra clave. Si está utilizandobreak
,continue
o alguna palabra clave similar, de hecho está utilizando unagoto
(Si está utilizandofor, while, foreach, do/loop
, está utilizando un goto condicional)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 que continúe la ejecución en un punto específico del programa . Alguien que lee 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 objetos restringidos , 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 un 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 las construcciones de nivel superior que admita el lenguaje.
En C, por ejemplo, creo que hay tres escenarios básicos donde un goto es apropiado.
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.
fuente
goto
. Los SSSM a menudo son buenas estructuras para usar, ya que separan el estado SM de la construcción de ejecución, pero en realidad no eliminan los "gotos".Seguramente depende del lenguaje de programación. La razón principal
goto
ha sido controvertida debido a sus efectos nocivos que surgen cuando el compilador le permite usarlo demasiado liberalmente. Pueden surgir problemas, por ejemplo, si le permite usargoto
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 rechazando por
goto
completo. Sin embargo, Java le permite usarreturn
dentro de unfinally
bloque y, por lo tanto, provocar que una excepción se trague inadvertidamente. El mismo problema sigue ahí: el compilador no está haciendo su trabajo. Eliminargoto
del idioma no lo ha solucionado.En C #,
goto
es tan seguro comobreak
,continue
,try/catch/finally
yreturn
. 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 definida y otras comprobaciones razonables del compilador.fuente
goto
no es malo? Si es así, ese es el caso de todos los lenguajes modernos utilizados habitualmente con unagoto
construcción, no solo C # ...Sí. Cuando sus bucles están anidados en varios niveles de profundidad,
goto
es la única forma de romper con elegancia 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
break
declaración etiquetada 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 elgoto
mal.fuente
Do
bucle. ¿Por qué? Porque puedo cambiar el bucle que necesita una ruptura profunda en unDo
bucle y escribirExit Do
y no hayGoTo
. Los bucles anidados suceden todo el tiempo. Romper las pilas ocurre un% de las veces.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:
Esto no tiene nada más que ver con la
goto
declaración de los lenguajes modernos, cuya existencia se debe simplemente a apoyar la creación de estructuras de código que no sean las proporcionadas por el lenguaje.En particular, el primer punto principal anterior ya está permitido y el segundo se limpia (si está
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
, solofor
. 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 observando más de mascaradagoto
de escapar lejos de las cimitarras de los fanáticos Djikstrarian, que -50 años después de la invención de laguages- moderna todavía quieren que 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 comprender que
goto
tiene que hacer frente a laGOTO
declaración sobre la que Djikstra fue convincente.fuente
break n
no está disponible en C ++, por lo tantogoto escape
, incluso siescape
no se requiere que salga del bucle n-ple.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 perjudicando significativamente la legibilidad, entonces 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.
fuente
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 ciclo donde el punto de decisión está en el medio del ciclo. 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.
fuente
goto
los que saltan en un bucle (si el idioma lo permite; desde el otro caso, saltando fuera del bucle en el medio, generalmente es trivial singoto
).goto
en gritar EL FLUJO DE CONTROL AQUÍ NO SE ADAPTA A LOS PATRONES DE PROGRAMACIÓN ESTRUCTURADA NORMAL . Debido a que los flujos de control que se ajustan a patrones de programación estructurados son más fáciles de razonar que aquellos que no lo hacen, uno debería intentar usar dichos patrones cuando sea posible; Si el código se ajusta a dichos patrones, no se debe gritar que no es así. Por otro lado, en los casos en que el código realmente no se ajusta a dichos patrones, gritar sobre él puede ser mejor que pretender que el código se ajusta cuando realmente no lo hace.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.)
fuente
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.
fuente
Yo diría que no. Si encuentra la necesidad de usar GOTO, apuesto a que es necesario rediseñar el código.
fuente
goto
puede ser útil cuando se transfiere el código de ensamblador heredado a C. En primera instancia, una conversión de instrucción por instrucción a C, que se usagoto
como reemplazo de labranch
instrucción del ensamblador , puede permitir una transferencia muy rápida.fuente
Yo diría que no. Siempre deben reemplazarse con una herramienta más específica para el problema que se está utilizando para resolver el goto (a menos que no esté disponible en su idioma). Por ejemplo, las declaraciones de interrupción y las excepciones resuelven problemas previamente resueltos por goto de escape de bucle y manejo de errores.
fuente
goto
generalmente están ausentes de esos idiomas.goto
los que lo más parecido a la semántica del dominio es un problema, cualquier otra cosa sería un truco sucio.