código escrito · artículos digitales de informática
 
Puntos de salida y estilo de programación
29.11.2004 :: Jaime Irurzun

Hace unos días, cuando nuestro profesor de programación nos explicó los bucles en Pascal, me extrañó bastante que no nombrara alguna sentencia que rompiera la secuencia de un while para forzar la salida del bucle en un momento determinado. Al final de la clase le pregunté si no existía, y me dijo que sí pero que por estilo de programación no quería que la usáramos. Que por eso no nos la había explicado. Me dijo que las entradas y salidas a los bucles tienen que ser naturales, y que antes que forzar con un brake o un exit, es mejor alterar el valor de la condición.

Leyendo un post de Refactoring, he recordado el consejo. Su autor, Jesús, dice que no es bueno hacer caso a este tipo de formalismos, ya que si bien son útiles en ciertos casos --por ejemplo puede interesar limitar las salidas de una función a un único punto para no duplicar código de liberación de recursos--, en otras situaciones pueden hacernos rizar el rizo demasiado y no recurrir a soluciones mucho más limpias y en definitiva elegantes --como podría ser la ruptura del bucle con un brake--. De hecho él recomienda esta técnica como método de refactorización.

¿Cómo lo véis? ¿Conviene ajustarse a los formalismos del estilo "un único punto de salida" o es mejor dejarse llevar con técnicas más inmediatas? ¿Realmente queda feo forzar la salida de un bucle con una cláusula concreta y es mejor alterar la condición?

comentarios (17) |


Comentarios del artículo
1 · Makinolo · 29.11.2004

Para esto soy bastante talibán, los breaks y los gotos deberian ser desterrados de una vez de todos los lenguajes de programación.

Si te acostumbras a leer el codigo con su ejecucion secuencial no tiene por que resultar antinatural meter una condicion adicional en un bucle para salir de el, algo como while (!salir) es bastante inteligible.
Si usas breaks puede que ganes algo en rendimiento, pero pierdes mucho mas en legibilidad del código y esto es muy importante si no trabajas solo, o si tienes que retomar los proyectos tras meses sin tocarlos.

Esto me recuerda un poco a la gente que usa for(;condicion;) para hacer un bucle, cuando podia usar un while, que es lo que es.

Yo llevo muchisimos años programando en diversos lenguajes y hace mucho tiempo que no uso un break o un goto... y no me ha pasado nada :)

2 · Jose Alberto · 29.11.2004

Hombre... yo diría que como casi todo, no conviene abusar.

A veces queda más claro poniendo un break que haciendo cumplir la condición o condiciones de bucles anidados. Pero repito, sólo bajo ciertas circunstancias.

3 · Walter Negro · 29.11.2004

Para aprender, es mejor usar la técnica que sugiere tu profesor.

Pero cuando las rutinas se complican, agregar flags de salida puede terminar generando una rutina mucho más compleja que lo que debería haber sido.

Al margen que ocaciona un consumo mayor de recursos (memoria por mayor cantidad de variables, procesador por ejecucion de mayor cantidad de lineas de codigo que en serán en su mayoría condiciones. Y las condiciones son las instrucciones más lentas en ejecutarse.

Pero como dijo Jose Alberto, no hay que abusar.
En general no uso un "return" dentro de un bucle, pero prefiero siempre usar un "break" o "exit" antes que complicar la condición del bucle.

4 · Antonio · 29.11.2004

¡NO a la programación espagueti! ;)

No sólo para aprender, romper bucles while o repeat y saltar con gotos no es la mejor forma de programar.

5 · abel · 29.11.2004

Pues seré marrullero, pero yo prefiero un break a tiempo que un while limpio pero rebuscado. Creo que estan son las típicos cosas que se deben enseñar como norma, pero que hay que matizar con la práctica diaria.

6 · edu · 29.11.2004

Lo correcto es programar sin breaks. Formalmente, para que un bucle se repita se ha de cumplir el invariante, y en el momento en que no sé cumpla se deja de repetir. Y se puede demostrar matemáticamente.
Si incluyes breaks, no podrás demostrarlo jamas.

7 · ebarbeito · 29.11.2004

Yo tampoco soy partidario del uso de instrucciones que rompen, en mayor o menor medida, un "buen estilo" de programación estructurada (break, continue, goto, exit...) y de hecho fue así como también me lo enseñaron.

Personalmente intento no valerme de las anteriores instrucciones citadas. Aunque tampoco creo que lo mejor sea ser totalmente estricto; por ejemplo, a la hora de utilizar una estructura de control múltiple (switch() {}) no veo por qué no emplear break's para finalizar con cada una de las opciones.

Pero para cosas como finalizaciones/salidas forzosas de bucles/funciones me decanto más por el uso de "variables de control". En los bucles, emplear una variable booleana que forme parte de la condición con un valor inicial y que éste cambie dentro del bucle en el momento deseado. O, en el caso de funciones que devuelven un valor, emplear siempre una variable de retorno ("result") que sea la que vaya captando los posibles valores devueltos y así emplear un único return(result); al final de la función (y no utilizar muchos return's por ahí desperdigados)

Es más cuestión de buenos hábitos que de otra cosa :) aunque ya digo, no creo que los "buenos hábitos" sean siempre la mejor opción jeje

Un saludo

8 · Jose Alfonso Suárez Moreno · 29.11.2004
Hay que saber bien que se quiere hacer y ser un buen programador para, en cada momento, aplicar las instrucciones necesarias para que el código se ejecute de forma fluida y precisa.

Desde luego el GOTO aquel del BASIC que hacia que los programas se convirtieran en una madeja enmarañada hay que evitarlo a toda costa. Es más, los modernos lenguajes lo han hecho desaparecer (aunque hay que reconocer que cuando no había otra forma de repetir un conjunto de instrucciones era una maravilla -a cada cosa su justo valor-).

En cuanto a a la norma de no enseñar BREAK, LOOP, EXIT y otros comandos para control de un bucle, creo que es una estafa, es una parte del lenguaje y hay que enseñarla, otra cosa es saber enseñar a programar debidamente.

A veces el uso de un BREAK permite la salida de un bucle sin tener que hacer más comprobaciones en el código posterior a donde se produce, evitando el uso de los IF; otras veces un LOOP permite saltar al inicio del bucle por el mismo motivo.

No creo que por "limpieza" en el código haya que sacrificar el uso de instrucciones que sabiendolas usar bien permiten al programador tener el control total del bucle. Y cuando se trabaja en equipo es buena costumbre documentar los programas y sobre todo las partes o instrucciones que pueden obscurecer el entendimiento del programa.

Y me reitero en lo dicho anteriormente, cuando se enseña hay que enseñarlo todo con todas sus consecuencias, en saber enseñar bien está la diferencia entre el uso y el abuso.

Un saludo,

9 · Walter Negro · 30.11.2004

Jose Alfonso, completamente de acuerdo contigo.
Todas las técnicas de programación deben ayudar al programador a hacer mejores programas.
El mejor programa posible, es un balance de legibilidad, simplicidad y velocidad.

El programador debe saber usar la mejor técnica para resolver de la mejor forma el problema planteado.

No soy amigo de los extremos, ninguna de las técnicas extremas logra hacer la legibilidad/simplicidad que tanto se pregona.

10 · José Luis Sánchez · 30.11.2004

Jaime: esto se lleva debatiendo desde antes de que tu nacieras. http://www.cs.utsa.edu/~wagner/CS3723/nogoto/harm2.html

Me toca para la clase de hoy ;-)

Saludos,

11 · Migugat · 30.11.2004

Personalmente, jamás usaria un goto o un break en un bucle. Puede ser que tu creas que utilizar un goto o un break puede simplificar mucho las cosas (de hecho, a ti te las simplificara a primera vista), pero si programas en un grupo de trabajo grande (15 programadores o mas) y los usas, te puedo asegurar que le complicaras la vida al resto de tus compañeros.
Si quieres mi consejo, no los uses!!. Yo llevo programando 10 años...y nunca me han hecho falta.

12 · FelipeM · 30.11.2004

Programar bien es un arte, por lo tanto hay que hacerlo lo más bonito posible, además al igual que el buen arte, todo el mundo lo podrá apreciar ;)

13 · paco · 30.11.2004

Hola

No creo que haya que rasgarse las vestiduras por utilizar un exit o un loop cuando tu eres el único dueño de tu código. El problema empieza cuando tu código es compartido. Pero... cuando el código es compartido, o utilizamos un convenio o los loops y los exit son los menores de los problemas. Las declaraciones de las variables, notación hungara, estilo en general puede volverse una pesadilla. Recuerdo de hace tiempo un programa de cuyo nombre no quiero acordarme, que nombraba las variables con una técnica que nadie conociamos. Simplemente identificar las variables era un problema.
Bueno, lo dicho. Creo que lo mejor es utilizar normas comunes entre todos los miembros de un equipo de programación. Todo lo que sea para obtener programas claros mantenibles por cualquiera del grupo.

Un abrazo

14 · Jaime Irurzun · 02.12.2004

Bueno, pues parece que hay opiniones para todos los gustos. En resumen parece que hay 3 puntos de vista:

- No usar NUNCA sentencias de salto.
- Usarlas en situaciones concretas pero sin abusar.
- Usarlas siempre para ganar legibilidad.

Me ha gustado mucho el hilo de mensajes. A ver si se forman más debates de este tipo. Intentaré plantear temas que generen tanto interés :)
Gracias a todos.

15 · pobrecito hablador · 07.12.2004

Las sentencias rupturistas no se deben usar en programación estructurada. Sin embargo, la programación estructurada sólo tiene cabida en un ámbito académico.

Cuando estás programando un proyecto grande nunca vas a seguir las indicaciones de codificación académicas. Si tienes que abortar la ejecución de una función es mucho más claro plantar un break o return aunque rompas la estructura. Eso si, siempre que lo uses debes poner un comentario apropiado indicando el motivo por el que lo haces.

Y para muestra un par de botones. ¿Qué es más claro?

while (true) {
elto = dame_elto();
// Condiciones excepcionales
if (elto == null) break; // final de bucle
if (es_invalido(elto)) break; // final de bucle
...

procesa(elto);
}

hay_elto = true;
while (hay_elto) {
elto = dame_elto();
hay_elto = (elto != null);
if (hay_elto) and es_invalido(elto) and ... {
procesa(elto)
}
}

for (int i=1; i if (es_par(i)) continue; // ignorar pares
if (f(i) > 0) continue; // ignorar mayores de 0

procesa(i);
}

for (int i=1; i if (f(i) >= 0) Y no_es_par(i) Y ...{
procesa(i);
}
}

Existen otras formas de implementar el caso estructurado, pero al fin y al cabo suponen hacer cosas fuera del bucle o duplicar código dentro o fuera.

A mi me parece más clara las no estructuradas: bucle infinito que va comprobando condiciones y aborta en cuando se cumple la primera. De hecho, una de las estructuras más usadas de los lenguajes orientados a objetos para el tratamiento de errores es no estructurada: las excepciones. Una excepción aborta no solo la función actual sino todas las apiladas hasta su manejador. En cuanto a la limpieza, existen clausulas especiales para indicar el código que debe ejecutarse en cualquier caso, haya salida normal o rupturista.

Un saludo.

16 · José Luis · 24.12.2004

Las técnicas de programación son recomendaciones teóricas pensadas para guiarnos en la mayoría de los casos, pero nunca se pueden interpretar como reglas rígidas. El sentido común y la experiencia deben dictar la mejor manera de enfocar la condición de parada de un bucle.

En general yo suelo preferir la claridad, y en ocasiones un bucle que para por un break (o un return si se aprovecha para salir de una función) son más claros que guardas muy elaboradas a partir de booleanos.

Lo que nunca jamás he necesitado usar -y ya llevo muchas líneas de código- ha sido utilizar goto. Por lo que deduzco que no sólo no es recomendable sino que tampoco es necesario.

17 · elinthbrain · 27.12.2004

En el ámbito de programación, uno, personalmente puede hacer lo que quiera, ¿Querés usár GOTO? ok usalo, ¿Querés usar BREAK? OK USALO!!! pero no me vengas a pedir trabajo porque te hecho a patadas en el culo!!!
Es lo que está pasando cada vez más, a lo que se llama un programador nunca te va a escribir un código con sentencias de escape, pero los que dicen "so soy pogamador" y resulta que en su púta vida lo que hace es programar para si mismo y nunca agarró un libro SERIO de programación, hace lo que quiere, porque dice "so me entiendo :P"
Hacer las cosas bien, como corresponden a un PROGRAMADOR no le cuesta nada, porque sabe como hacerlo y bien, pero al que no es programador de en serio...
Mención a parte merecen los programadores de videojuegos, que por real necesidad de verdadera potencia hacen uso de muchas sentencias de escape y de salto, dado la extrema complejidad de los algoritmos que realizan... en ensamblador no existe la posibilidad de no usarlas... pero es la real necesidad de potencia...














































Creative Commons - Jaime Irurzun y Aitor Martin