Todos conocen las Cartas de Dijkstra al editor: vaya a la declaración considerada perjudicial (también aquí transcripción .html y aquí .pdf) y ha habido un impulso formidable desde ese momento para evitar la declaración goto siempre que sea posible. Si bien es posible usar goto para producir un código extenso e imposible de mantener, no obstante permanece en los lenguajes de programación modernos . Incluso la estructura avanzada de control de continuación en Scheme puede describirse como un goto sofisticado.
¿Qué circunstancias justifican el uso de goto? ¿Cuándo es mejor evitarlo?
Como una pregunta de seguimiento: C proporciona un par de funciones, setjmp y longjmp, que proporcionan la capacidad de ir no solo dentro del marco de pila actual sino dentro de cualquiera de los marcos de llamada. ¿Deberían considerarse estos tan peligrosos como el goto? ¿Más peligroso?
El propio Dijkstra lamentó ese título, del que no era responsable. Al final de EWD1308 (también aquí .pdf) escribió:
Finalmente una historia corta para el registro. En 1968, las Comunicaciones de la ACM publicaron un texto mío bajo el título " La declaración Goto considerada dañina ", que en años posteriores sería mencionada con mayor frecuencia, sin embargo, lamentablemente, a menudo por autores que no habían visto más de ella título, que se convirtió en una piedra angular de mi fama al convertirse en una plantilla: veríamos todo tipo de artículos bajo el título "X considerado dañino" para casi cualquier X, incluido uno titulado "Dijkstra considerado dañino". ¿Pero que había pasado? Había presentado un documento con el título " Un caso contra la declaración Goto", que, para acelerar su publicación, el editor había cambiado a una" carta al Editor ", ¡y en el proceso le había dado un nuevo título de su propia invención! El editor era Niklaus Wirth.
Un artículo clásico bien pensado sobre este tema, que debe coincidir con el de Dijkstra, es Programación estructurada con Ir a declaraciones , por Donald E. Knuth. Leer ambos ayuda a restablecer el contexto y una comprensión no dogmática del tema. En este documento, se informa la opinión de Dijkstra sobre este caso y es aún más fuerte:
Donald E. Knuth: Creo que al presentar tal punto de vista no estoy en desacuerdo con las ideas de Dijkstra, ya que recientemente escribió lo siguiente: "Por favor, no caigas en la trampa de creer que soy terriblemente dogmático sobre [el ir a la declaración]. ¡Tengo la incómoda sensación de que otros están haciendo de ella una religión, como si los problemas conceptuales de la programación pudieran resolverse con un solo truco, con una forma simple de disciplina de codificación! "
fuente
goto
.goto
: piratear herramientas de programación estructuradas para implementar agoto
.Respuestas:
Las siguientes declaraciones son generalizaciones; Si bien siempre es posible alegar una excepción, por lo general (en mi experiencia y humilde opinión) no vale la pena arriesgarse.
Notas a pie de página a lo anterior:
Con respecto al punto 2, considere el siguiente código:
En el punto "hacer algo" en el código, podemos afirmar con alta confianza que
a
es mayor queb
. (Sí, estoy ignorando la posibilidad de desbordamiento de enteros sin atrapar. No empañemos un ejemplo simple).Por otro lado, si el código se hubiera leído de esta manera:
La multiplicidad de formas de llegar a la etiqueta 10 significa que tenemos que trabajar mucho más para tener confianza en las relaciones entre
a
yb
en ese punto. (De hecho, ¡en el caso general es indecidible!)Con respecto al punto 4, toda la noción de "ir a algún lado" en el código es solo una metáfora. Nada está realmente "yendo" a ninguna parte dentro de la CPU, excepto electrones y fotones (por el calor residual). A veces renunciamos a una metáfora para otra, más útil, una. Recuerdo haber encontrado (¡hace unas décadas!) Un lenguaje donde
se implementó en una máquina virtual compilando action-1 y action-2 como rutinas sin parámetros fuera de línea, luego usando un código de operación de VM de dos argumentos que usaba el valor booleano de la condición para invocar uno u otro. El concepto era simplemente "elegir qué invocar ahora" en lugar de "ir aquí o ir allá". De nuevo, solo un cambio de metáfora.
fuente
true
yfalse
son de diferentes tipos), y cada rama de un if / else es básicamente una lambda.goto
en un lenguaje de programación moderno (Go) stackoverflow.com/a/11065563/3309046 .Un compañero de trabajo mío dijo que la única razón para usar un GOTO es si te has programado tanto en una esquina que es la única salida. En otras palabras, un diseño adecuado con anticipación y no necesitará usar un GOTO más adelante.
Pensé que este cómic ilustra que bellamente "podría reestructurar el flujo del programa, o usar un pequeño 'GOTO' en su lugar". Un GOTO es una salida débil cuando tienes un diseño débil. Los velociraptores se aprovechan de los débiles .
fuente
A veces es válido usar GOTO como alternativa al manejo de excepciones dentro de una sola función:
El código COM parece caer en este patrón con bastante frecuencia.
fuente
Solo recuerdo haber usado un goto una vez. Tenía una serie de cinco bucles contados anidados y necesitaba poder salir de toda la estructura desde el interior temprano en función de ciertas condiciones:
Podría haber declarado fácilmente una variable de corte booleana y usarla como parte del condicional para cada ciclo, pero en este caso decidí que un GOTO era tan práctico y tan legible.
Ningún velociraptor me atacó.
fuente
goto
y nos dio una programación estructurada también rechazó los primeros retornos, por la misma razón. Todo se reduce a qué tan legible es el código, qué tan claramente expresa la intención del programador. Crear una función con el único propósito de evitar el uso de una palabra clave difamada resulta en una mala cohesión: la cura es peor que la enfermedad.goto
, se puede especificar explícitamente el objetivo. Conbreak 5;
, (1) tengo que contar los cierres de bucle para encontrar el destino; y (2) si la estructura del bucle alguna vez cambia, bien puede requerir cambiar ese número para mantener el destino correcto. Si voy a evitargoto
, entonces la ganancia debería estar en no tener que rastrear manualmente cosas como esas.Ya tuvimos esta discusión y mantengo mi punto de vista .
Además, estoy harto de personas que describen estructuras de lenguaje de nivel superior como "
goto
disfrazadas" porque claramente no han entendido nada . Por ejemplo:Eso es una completa tontería. Cada estructura de control puede implementarse en términos de,
goto
pero esta observación es completamente trivial e inútil.goto
no se considera dañino debido a sus efectos positivos, sino a sus consecuencias negativas, que han sido eliminadas por la programación estructurada.Del mismo modo, decir "GOTO es una herramienta, y como todas las herramientas, se puede usar y abusar" está completamente fuera de lugar. Ningún trabajador de la construcción moderna usaría una roca y afirmaría que "es una herramienta". Las rocas han sido reemplazadas por martillos.
goto
ha sido reemplazado por estructuras de control. Si el trabajador de la construcción quedara varado en la naturaleza sin un martillo, por supuesto que usaría una roca en su lugar. Si un programador tiene que usar un lenguaje de programación inferior que no tiene la función X, bueno, por supuesto, puede que tenga que usarlogoto
. Pero si lo usa en otro lugar en lugar de la característica de lenguaje apropiada, claramente no ha entendido el idioma correctamente y lo usa incorrectamente. Es realmente tan simple como eso.fuente
goto
. Tienes razón en la medida en que no ofrezco un argumento en contragoto
per se, no tenía la intención de hacerlo, por lo que no hay dudas.Goto es extremadamente bajo en mi lista de cosas para incluir en un programa solo por el simple hecho de hacerlo. Eso no significa que sea inaceptable.
Goto puede ser bueno para las máquinas de estado. Una declaración de cambio en un bucle es (en orden de importancia típica): (a) en realidad no representativa del flujo de control, (b) feo, (c) potencialmente ineficiente dependiendo del lenguaje y el compilador. Entonces terminas escribiendo una función por estado y haciendo cosas como "return NEXT_STATE;" que incluso parecen goto.
Por supuesto, es difícil codificar máquinas de estado de una manera que las haga fáciles de entender. Sin embargo, ninguna de esas dificultades tiene que ver con el uso de goto, y ninguna de ellas puede reducirse mediante el uso de estructuras de control alternativas. A menos que su lenguaje tenga una construcción de 'máquina de estado'. La mía no.
En esas raras ocasiones en que su algoritmo es realmente más comprensible en términos de una ruta a través de una secuencia de nodos (estados) conectados por un conjunto limitado de transiciones permisibles (gotos), en lugar de por un flujo de control más específico (bucles, condicionales, etc.) ), entonces eso debería ser explícito en el código. Y deberías dibujar un bonito diagrama.
setjmp / longjmp puede ser bueno para implementar excepciones o comportamientos similares a las excepciones. Si bien no se elogian universalmente, las excepciones generalmente se consideran una estructura de control "válida".
setjmp / longjmp son 'más peligrosos' que goto en el sentido de que son más difíciles de usar correctamente, no importa mucho.
Sacar Goto de C no facilitaría escribir un buen código en C. De hecho, preferiría perder el punto de que se supone que C es capaz de actuar como un lenguaje ensamblador glorificado.
Luego serán "punteros considerados dañinos", luego "tipear pato considerado dañino". Entonces, ¿quién quedará para defenderte cuando vengan a quitar tu construcción de programación insegura? Eh?
fuente
En Linux: Usando goto In Kernel Code en Kernel Trap, hay una discusión con Linus Torvalds y un "chico nuevo" sobre el uso de GOTOs en el código de Linux. Hay algunos puntos muy buenos allí y Linus se vistió con esa arrogancia habitual :)
Algunos pasajes:
-
-
fuente
goto cleanup_and_exit
es uno de los pocos "buenos" usos de la izquierda Goto ahora que tenemosfor
,while
yif
para administrar nuestro flujo de control. Ver también: programmers.stackexchange.com/a/154980En C,
goto
solo funciona dentro del alcance de la función actual, que tiende a localizar posibles errores.setjmp
ylongjmp
son mucho más peligrosos, no son locales, complicados y dependen de la implementación. Sin embargo, en la práctica, son demasiado oscuros y poco comunes como para causar muchos problemas.Creo que el peligro de
goto
en C es muy exagerado. Recuerde que losgoto
argumentos originales tuvieron lugar en la época de idiomas como el BASIC pasado de moda, donde los principiantes escribían código de espagueti como este:Aquí Linus describe un uso apropiado de
goto
: http://www.kernel.org/doc/Documentation/CodingStyle (capítulo 7).fuente
setjmp
/longjmp
solo se especificó cuando se usaron como un medio para saltar a un lugar dentro de un alcance desde otros lugares dentro de ese mismo alcance. Una vez que el control abandona el ámbito dondesetjmp
se ejecuta, cualquier intento de usolongjmp
en la estructura creada porsetjmp
dará como resultado un comportamiento indefinido.GOTO A * 40 + B * 200 + 30
. No es difícil ver cómo esto fue muy útil y muy peligroso.Hoy en día, es difícil ver el gran problema acerca de la
GOTO
declaración porque la gente de "programación estructurada" en su mayoría ganó el debate y los lenguajes de hoy tienen estructuras de flujo de control suficientes para evitarGOTO
.Cuente el número de
goto
s en un programa moderno de C. Ahora agregue el número debreak
,continue
yreturn
declaraciones. Por otra parte, añadir el número de veces que utiliceif
,else
,while
,switch
ocase
. Eso es aproximadamente cuántosGOTO
s habría tenido su programa si estuviera escribiendo en FORTRAN o BASIC en 1968 cuando Dijkstra escribió su carta.Los lenguajes de programación en ese momento carecían de flujo de control. Por ejemplo, en el Dartmouth BASIC original:
IF
declaraciones no teníanELSE
. Si querías uno, tenías que escribir:Incluso si su
IF
estado de cuenta no necesitaba unELSE
, todavía estaba limitado a una sola línea, que generalmente consistía en unGOTO
.No hubo
DO...LOOP
declaración. Para los que no sonFOR
bucles, tenía que finalizar el bucle de forma explícitaGOTO
oIF...GOTO
volver al principio.Allí no estaba
SELECT CASE
. Tuviste que usarON...GOTO
.Por lo tanto, que terminó con una gran cantidad de
GOTO
s en su programa. Y no podría depender de la restricción deGOTO
s dentro de una sola subrutina (porqueGOSUB...RETURN
era un concepto tan débil de subrutinas), por lo que estosGOTO
s podrían ir a cualquier parte . Obviamente, esto hizo que el control fluyera difícil de seguir.De aquí es de donde
GOTO
vino el anti- movimiento.fuente
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
. Escribir código de esa manera evita cualquier rama o salto tomado en el caso común de la línea principal, pero hace que las cosas sean difíciles de seguir. La evitación de ramificaciones en el código de ensamblaje puede ser peor, si algunas ramificaciones están limitadas a, por ejemplo, +/- 128 bytes y, a veces, no tienen pares complementarios (por ejemplo, "cjne" existe pero no "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: ...
. No es un patrón de codificación muy agradable, pero cuando los ciclos individuales cuentan, uno hace esas cosas. Por supuesto, en la década de 1960, tales niveles de optimización eran más importantes que hoy, especialmente porque las CPU modernas a menudo requieren optimizaciones extrañas, y los sistemas de compilación justo a tiempo pueden aplicar código de optimización para CPU que no existían cuando El código en cuestión fue escrito.Ir a puede proporcionar una especie de sustituto para el manejo de excepciones "reales" en ciertos casos. Considerar:
Obviamente, este código se simplificó para ocupar menos espacio, así que no te obsesiones con los detalles. Pero considere una alternativa que he visto demasiadas veces en el código de producción por los codificadores yendo a longitudes absurdas para evitar usar goto:
Ahora funcionalmente este código hace exactamente lo mismo. De hecho, el código generado por el compilador es casi idéntico. Sin embargo, en el afán del programador por apaciguar a Nogoto (el temido dios de la reprimenda académica), este programador ha roto por completo el idioma subyacente que
while
representa el bucle e hizo un número real sobre la legibilidad del código. Esto no es mejorEntonces, la moraleja de la historia es que si te encuentras recurriendo a algo realmente estúpido para evitar usar goto, entonces no lo hagas.
fuente
break
declaraciones estén dentro de una estructura de control deja en claro exactamente lo que hacen. Con elgoto
ejemplo, la persona que lee el código tiene que revisar el código para encontrar la etiqueta, que en teoría podría estar antes de la estructura de control. No tengo suficiente experiencia con el estilo antiguo C para juzgar que uno es definitivamente mejor que el otro, pero hay compensaciones en ambos sentidos.break
s estén dentro de un bucle deja en claro exactamente que salen del bucle . Eso no es "exactamente lo que hacen", ya que en realidad, ¡no hay un bucle en absoluto! Nada de eso tiene posibilidades de repetirse, pero eso no está claro hasta el final. El hecho de que tenga un "bucle" que nunca se ejecuta más de una vez, significa que las estructuras de control están siendo abusadas. Con elgoto
ejemplo, el programador puede decirgoto error_handler;
. Es más explícito, y aún menos difícil de seguir. (Ctrl + F, "error_handler:" para encontrar el objetivo. Intenta hacerlo con "}".)Donald E. Knuth respondió a esta pregunta en el libro "Literate Programming", 1992 CSLI. En P. 17 hay un ensayo " Programación estructurada con declaraciones Goto " (PDF). Creo que el artículo podría haber sido publicado en otros libros también.
El artículo describe la sugerencia de Dijkstra y describe las circunstancias en que esto es válido. Pero también da una serie de contraejemplos (problemas y algoritmos) que no pueden reproducirse fácilmente utilizando solo bucles estructurados.
El artículo contiene una descripción completa del problema, la historia, los ejemplos y los contraejemplos.
fuente
Goto lo consideró útil.
Comencé a programar en 1975. Para los programadores de la década de 1970, las palabras "goto considerado dañino" decían más o menos que valía la pena probar nuevos lenguajes de programación con estructuras de control modernas. Probamos los nuevos idiomas. Nos convertimos rápidamente. Nunca volvimos.
Nunca volvimos, pero si eres más joven, nunca has estado allí en primer lugar.
Ahora, un fondo en lenguajes de programación antiguos puede no ser muy útil, excepto como un indicador de la edad del programador. No obstante, los programadores más jóvenes carecen de estos antecedentes, por lo que ya no entienden el mensaje que el lema "goto considerado dañino" transmitió a su público objetivo en el momento en que se introdujo.
Los lemas que uno no entiende no son muy esclarecedores. Probablemente sea mejor olvidar tales lemas. Tales consignas no ayudan.
Sin embargo, este eslogan particular, "Goto considerado dañino", ha adquirido una vida propia de los no muertos.
¿No se puede abusar de goto? Respuesta: claro, pero ¿y qué? Prácticamente todos los elementos de programación pueden ser abusados. Los humildes,
bool
por ejemplo, son abusados con más frecuencia de lo que algunos de nosotros quisiéramos creer.Por el contrario, no recuerdo haber conocido una sola instancia real de abuso de goto desde 1990.
El mayor problema con goto probablemente no sea técnico, sino social. Los programadores que no saben mucho a veces parecen sentir que despreciar el goto los hace sonar inteligentes. Puede que tenga que satisfacer a tales programadores de vez en cuando. Así es la vida.
Lo peor de goto hoy es que no se usa lo suficiente.
fuente
Atraído por Jay Ballou agregando una respuesta, agregaré £ 0.02. Si Bruno Ranschaert aún no lo hubiera hecho, habría mencionado el artículo de Knuth "Programación estructurada con declaraciones GOTO".
Una cosa que no he visto discutido es el tipo de código que, aunque no es exactamente común, se enseñó en los libros de texto de Fortran. Cosas como el rango extendido de un bucle DO y subrutinas de código abierto (recuerde, esto sería Fortran II, Fortran IV o Fortran 66, no Fortran 77 o 90). Existe al menos una posibilidad de que los detalles sintácticos sean inexactos, pero los conceptos deben ser lo suficientemente precisos. Los fragmentos en cada caso están dentro de una sola función.
Tenga en cuenta que el excelente pero anticuado (y agotado) libro ' The Elements of Programming Style, 2nd Edn ' de Kernighan & Plauger incluye algunos ejemplos reales de abuso de GOTO de los libros de texto de programación de su época (finales de los 70). Sin embargo, el material a continuación no es de ese libro.
Rango extendido para un ciclo DO
Una razón para tales tonterías era la buena tarjeta perforada pasada de moda. Puede notar que las etiquetas (¡muy fuera de secuencia porque ese era el estilo canónico!) Están en la columna 1 (en realidad, tenían que estar en las columnas 1-5) y el código está en las columnas 7-72 (la columna 6 fue la continuación columna de marcador). Las columnas 73-80 recibirían un número de secuencia, y había máquinas que clasificaban los mazos de cartas perforadas en orden de número de secuencia. Si tuviera su programa en tarjetas secuenciadas y necesitara agregar algunas tarjetas (líneas) en el medio de un bucle, tendría que volver a ejecutar todo después de esas líneas adicionales. Sin embargo, si reemplaza una tarjeta con el material GOTO, puede evitar volver a secuenciar todas las tarjetas: simplemente coloca las nuevas tarjetas al final de la rutina con nuevos números de secuencia. Considere que es el primer intento de 'computación verde'
Ah, también podrías notar que estoy engañando y no gritando: Fortran IV se escribió en mayúsculas normalmente.
Subrutina de código abierto
El GOTO entre las etiquetas 76 y 54 es una versión de goto computarizado. Si la variable i tiene el valor 1, pase a la primera etiqueta de la lista (123); si tiene el valor 2, pase al segundo, y así sucesivamente. El fragmento del 76 al goto calculado es la subrutina de código abierto. Era un fragmento de código ejecutado como una subrutina, pero escrito en el cuerpo de una función. (Fortran también tenía funciones de declaración, que eran funciones integradas que se ajustaban en una sola línea).
Había construcciones peores que el goto calculado: se podían asignar etiquetas a las variables y luego usar un goto asignado. El goto asignado en Google me dice que fue eliminado de Fortran 95. Marque uno para la revolución de programación estructurada que podría decirse que comenzó en público con la carta o artículo "GOTO Considered Damful" de Dijkstra.
Sin algún conocimiento del tipo de cosas que se hicieron en Fortran (y en otros idiomas, la mayoría de las cuales han quedado en el camino), es difícil para nosotros los recién llegados entender el alcance del problema con el que Dijkstra estaba lidiando. Diablos, no comencé a programar hasta diez años después de que se publicó esa carta (pero tuve la desgracia de programar en Fortran IV por un tiempo).
fuente
goto
'en la naturaleza', la pregunta Se busca: Algoritmo de ordenación Bose-Hibbard de trabajo muestra algún código (Algol 60) publicado en 1963. El diseño original no se compara con los estándares de codificación modernos. El código aclarado (sangrado) sigue siendo bastante inescrutable. Lasgoto
declaraciones allí hacen que sea (muy) difícil entender lo que está haciendo el algoritmo.No hay cosas que GOTO considere dañinas .
GOTO es una herramienta, y como todas las herramientas, se puede usar y abusar de ella .
Sin embargo, hay muchas herramientas en el mundo de la programación que tienden a ser abusadas más que a ser utilizadas , y GOTO es una de ellas. la declaración WITH de Delphi es otra.
Personalmente, no uso ninguno de los códigos típicos , pero he tenido el uso extraño de GOTO y WITH que estaban garantizados, y una solución alternativa habría contenido más código.
La mejor solución sería que el compilador le advirtiera que la palabra clave estaba contaminada , y tendría que rellenar un par de directivas pragma alrededor de la declaración para deshacerse de las advertencias.
Es como decirles a tus hijos que no corran con tijeras . Las tijeras no son malas, pero su uso no es la mejor manera de mantener su salud.
fuente
goto
palabra clave se borró de C #, el concepto de "saltar aquí" todavía existe en IL. Se puede construir fácilmente un bucle infinito sin la palabra clave goto. Si esta falta de garantía de que el código llamado volverá, en su opinión, significa "incapaz de razonar sobre el código", entonces diría que nunca tuvimos esa capacidad.goto
in C # no es un verdadero "goto" en el sentido original de la palabra. Es una versión mucho más débil que solo permite saltar dentro de una función. El sentido en el que estoy usando "goto" permite saltar a cualquier parte del proceso. Entonces, aunque C # tiene una palabra clave "goto", podría decirse que nunca ha tenido un goto real. Sí, hay un goto real disponible a nivel IL, de la misma manera que cuando un lenguaje se compila en ensamblador. Pero el programador está protegido de eso, no puede usarlo en circunstancias normales, por lo que no cuenta.Nunca lo fue, siempre que pudieras pensar por ti mismo.
fuente
Desde que comencé a hacer algunas cosas en el kernel de Linux, los gotos no me molestan tanto como antes. Al principio me horroricé al ver que ellos (chicos del kernel) añadían gotos a mi código. Desde entonces me he acostumbrado al uso de gotos, en algunos contextos limitados, y ahora ocasionalmente los usaré yo mismo. Por lo general, es un goto que salta al final de una función para realizar algún tipo de limpieza y rescate, en lugar de duplicar esa misma limpieza y rescate en varios lugares de la función. Y, por lo general, no es algo lo suficientemente grande como para pasar a otra función; por ejemplo, liberar algunas variables localmente (k) mal asignadas es un caso típico.
He escrito código que usó setjmp / longjmp solo una vez. Estaba en un programa secuenciador de batería MIDI. La reproducción se realizó en un proceso separado de toda interacción del usuario, y el proceso de reproducción utilizó memoria compartida con el proceso de la interfaz de usuario para obtener la información limitada que necesitaba para realizar la reproducción. Cuando el usuario quería detener la reproducción, el proceso de reproducción simplemente hacía un "salto al principio" para volver a comenzar, en lugar de un complicado desenrollamiento de donde se estaba ejecutando cuando el usuario quería que se detuviera. Funcionó muy bien, fue simple y nunca tuve ningún problema o error relacionado con eso en esa instancia.
setjmp / longjmp tienen su lugar, pero ese lugar es uno que probablemente no visitará, pero de vez en cuando.
Editar: acabo de mirar el código. En realidad fue siglongjmp () lo que usé, no longjmp (no es que sea un gran problema, pero había olvidado que siglongjmp incluso existía).
fuente
Si está escribiendo una VM en C, resulta que el uso de gotos computados (gcc) es el siguiente:
funciona mucho más rápido que el interruptor convencional dentro de un bucle.
fuente
&&op_inc
ciertamente no compila, porque (la izquierda)&
espera un valor de l, pero (la derecha)&
produce un valor de r.Porque
goto
puede usarse para confundir metaprogramaciónGoto
es una expresión de control de alto nivel y de bajo nivel , y como resultado simplemente no tiene un patrón de diseño apropiado para la mayoría de los problemas.Es de bajo nivel en el sentido de que un Goto es una operación primitiva que implementa algo superior al igual que
while
oforeach
o algo así.Es de alto nivel en el sentido de que, cuando se usa de ciertas maneras, toma un código que se ejecuta en una secuencia clara, de manera ininterrumpida, excepto los bucles estructurados, y lo transforma en piezas de lógica que son, con suficiente
goto
s, un agarre -Bolsa de lógica reensamblada dinámicamente.Por lo tanto, hay una prosaica y un mal lado a
goto
.El lado prosaico es que un goto que apunta hacia arriba puede implementar un bucle perfectamente razonable y un goto que apunta hacia abajo puede hacer un
break
o perfectamente razonablereturn
. Por supuesto, un realwhile
,break
oreturn
sería mucho más legible, ya que el pobre humano no tendría que simular el efecto delgoto
para obtener el panorama general. Entonces, una mala idea en general.El lado malvado implica una rutina que no usa goto durante un tiempo, se rompe o regresa, sino que se usa para lo que se llama lógica de espagueti . En este caso, el desarrollador goto-happy está construyendo piezas de código a partir de un laberinto de goto's, y la única forma de entenderlo es simulando mentalmente en su conjunto, una tarea terriblemente agotadora cuando hay muchos goto's. Quiero decir, imagina el problema de evaluar el código donde el
else
no es precisamente un inverso delif
, donde losif
s anidados podrían permitir algunas cosas que fueron rechazadas por el exteriorif
, etc., etc.Finalmente, para cubrir realmente el tema, debemos tener en cuenta que, esencialmente, todos los primeros idiomas, excepto Algol, inicialmente solo hicieron declaraciones únicas sujetas a sus versiones de
if-then-else
. Entonces, la única forma de hacer un bloque condicional eragoto
rodeándolo usando un condicional inverso. Loco, lo sé, pero he leído algunas especificaciones antiguas. Recuerde que las primeras computadoras fueron programadas en código de máquina binario, así que supongo que cualquier tipo de HLL era un salvavidas; Supongo que no fueron demasiado quisquillosos sobre exactamente qué características de HLL obtuvieron.Habiendo dicho todo lo que solía incluir uno
goto
en cada programa, escribí "solo para molestar a los puristas" .fuente
Negar el uso de la declaración GOTO a los programadores es como decirle a un carpintero que no use un martillo ya que podría dañar la pared mientras está clavando un clavo. Un programador real sabe cómo y cuándo usar un GOTO. He seguido algunos de estos llamados 'Programas Estructurados'. He visto ese código horrible solo para evitar usar un GOTO, para poder dispararle al programador. Ok, en defensa del otro lado, también he visto un código de espagueti real y, una vez más, esos programadores también deberían recibir un disparo.
Aquí hay solo un pequeño ejemplo de código que he encontrado.
-----------------------O----------------------
fuente
goto
- y sabe por qué . Evitar una construcción de lenguaje tabú porque $ programacion_guru lo dijo, esa es la definición misma de la programación de culto de carga."En este enlace http://kerneltrap.org/node/553/2131 "
Irónicamente, la eliminación del goto introdujo un error: se omitió la llamada spinlock.
fuente
El documento original debe considerarse como "GOTO incondicional considerado perjudicial". En particular, abogaba por una forma de programación basada en construcciones condicionales (
if
) e iterativas (while
), en lugar de las pruebas y saltos comunes al código inicial.goto
sigue siendo útil en algunos idiomas o circunstancias, donde no existe una estructura de control adecuada.fuente
Casi el único lugar en el que estoy de acuerdo con que Goto podría usarse es cuando necesita lidiar con errores, y cada punto particular en que se produce un error requiere un manejo especial.
Por ejemplo, si está tomando recursos y usando semáforos o mutexes, debe tomarlos en orden y siempre debe liberarlos de la manera opuesta.
Algunos códigos requieren un patrón muy extraño de capturar estos recursos, y no puede simplemente escribir una estructura de control fácil de mantener y comprender para manejar correctamente tanto la captura como la liberación de estos recursos para evitar un punto muerto.
Siempre es posible hacerlo bien sin goto, pero en este caso y en algunos otros, Goto es en realidad la mejor solución principalmente para la legibilidad y la facilidad de mantenimiento.
-Adán
fuente
Un uso moderno de GOTO es el compilador de C # para crear máquinas de estado para enumeradores definidos por el rendimiento.
GOTO es algo que deberían usar los compiladores y no los programadores.
fuente
goto
. Donde podríamos usargoto
en una máquina de estado codificada a mano para implementar un enumerador, podemos usaryield
en su lugar.Hasta que C y C ++ (entre otros culpables) tengan roturas roturas y continúen, goto continuará teniendo un papel.
fuente
Si GOTO fuera malvado, los compiladores serían malvados porque generan JMP. Si saltar a un bloque de código, especialmente después de un puntero, fuera inherentemente malo, la instrucción RETurn sería malvada. Más bien, el mal está en el potencial de abuso.
A veces he tenido que escribir aplicaciones que tenían que hacer un seguimiento de una serie de objetos en los que cada objeto tenía que seguir una secuencia intrincada de estados en respuesta a los eventos, pero todo era definitivamente de un solo hilo. Una secuencia típica de estados, si se representa en pseudocódigo sería:
Estoy seguro de que esto no es nuevo, pero la forma en que lo manejé en C (++) fue definir algunas macros:
Luego (suponiendo que el estado es inicialmente 0) la máquina de estados estructurados anterior se convierte en el código estructurado:
Con una variación de esto, puede haber CALL y RETURN, por lo que algunas máquinas de estado pueden actuar como subrutinas de otras máquinas de estado.
¿Es inusual? Si. ¿Toma algo de aprendizaje por parte del mantenedor? Si. ¿Vale la pena ese aprendizaje? Creo que sí. ¿Se podría hacer sin GOTOs que saltan en bloques? No
fuente
Lo evito ya que un compañero de trabajo / gerente, sin duda, cuestionará su uso, ya sea en una revisión de código o cuando se encuentren con él. Si bien creo que tiene usos (el caso de manejo de errores, por ejemplo), se encontrará con algún otro desarrollador que tendrá algún tipo de problema.
Que no vale la pena.
fuente
De hecho, me vi obligado a usar un goto, porque literalmente no podía pensar en una mejor (más rápida) forma de escribir este código:
Tenía un objeto complejo y necesitaba hacer alguna operación sobre él. Si el objeto estaba en un estado, entonces podría hacer una versión rápida de la operación, de lo contrario tenía que hacer una versión lenta de la operación. La cuestión era que, en algunos casos, en medio de la operación lenta, era posible darse cuenta de que esto podría haberse hecho con la operación rápida.
Esto estaba en una pieza de código de interfaz de usuario en tiempo real, por lo que honestamente creo que un GOTO estaba justificado aquí.
Hugo
fuente
Casi todas las situaciones en las que se puede usar un goto, puedes hacer lo mismo con otras construcciones. Goto es usado por el compilador de todos modos.
Yo personalmente nunca lo uso explícitamente, nunca lo necesito.
fuente
Una cosa que no he visto en ninguna de las respuestas aquí es que una solución 'goto' suele ser más eficiente que una de las soluciones de programación estructurada mencionadas a menudo.
Considere el caso de muchos bucles anidados, donde usar 'goto' en lugar de un montón de
if(breakVariable)
secciones es obviamente más eficiente. La solución "Poner tus loops en una función y usar return" a menudo es totalmente irracional. En el caso probable de que los bucles estén usando variables locales, ahora tiene que pasarlos todos a través de los parámetros de la función, potencialmente manejando un montón de dolores de cabeza adicionales que surgen de eso.Ahora considere el caso de limpieza, que he usado con bastante frecuencia, y es tan común que presumiblemente fue responsable de la estructura try {} catch {} que no está disponible en muchos idiomas. El número de comprobaciones y variables adicionales que se requieren para lograr lo mismo son mucho peores que las una o dos instrucciones para dar el salto, y nuevamente, la solución de función adicional no es una solución en absoluto. No puedes decirme que es más manejable o más legible.
Ahora el espacio de código, el uso de la pila y el tiempo de ejecución pueden no ser lo suficientemente importantes en muchas situaciones para muchos programadores, pero cuando se encuentra en un entorno incrustado con solo 2 KB de espacio de código para trabajar, 50 bytes de instrucciones adicionales para evitar uno claramente definido 'goto' es simplemente ridículo, y esta no es una situación tan rara como creen muchos programadores de alto nivel.
La afirmación de que 'goto es dañino' fue muy útil para avanzar hacia una programación estructurada, incluso si siempre fue una generalización excesiva. En este punto, todos lo hemos escuchado lo suficiente como para tener cuidado de usarlo (como deberíamos). Cuando obviamente es la herramienta adecuada para el trabajo, no necesitamos tenerle miedo.
fuente
Puede usarlo para romper un bucle profundamente anidado, pero la mayoría de las veces se puede refactorizar su código para que sea más limpio sin bucles profundamente anidados.
fuente