Portada arrow Artículos arrow Break y continue para salir de un bucle: un goto encubierto.
Break y continue para salir de un bucle: un goto encubierto.
miércoles, 11 de abril de 2007

Algunos lenguajes han heredado del C una curiosa forma de salir de los bucles: las instrucciones break y continue. Entre estos lenguajes se encuentran Java, C#, C++, php, python, Delphi... en fin, un montón.

Utilizar estas instrucciones para salir de un bucle supone, aunque no lo parezca, incluir un salto incondicional en el interior del bucle, es decir, el equivalente a la maltrecha instrucción goto.

Como en todo, hay partidarios y detractores de estas dos instrucciones. En general, no son demasiado problemáticas si no se utilizan indiscriminadamente, ya que su ámbito de aplicación es muy reducido: siempre deben estar en el interior de un bucle.

La instrucción break permite detener incondicionalmente un bucle. Es decir, si se alcanza esta instrucción, se pasa bruscamente a la instrucción siguiente al fin del bucle. Veamos un ejemplo (Como de costumbre, en C#):

int i;
for (i = 0; i < 10; i++)
{
   Console.WriteLine("valor de i: {0}", i);
   if (i > 4)
   {
      break;
   }
}
Console.WriteLine("Fin del bucle");
Console.WriteLine("valor de i: {0}", i);
 

El resultado de la ejecución es el siguiente:

valor de i: 0
valor de i: 1
valor de i: 2
valor de i: 3
valor de i: 4
valor de i: 5
Fin del bucle
valor de i: 5
 

Realmente, lo que hemos hecho es saltar a la instrucción siguiente al fin del bucle cuando se alcanza el break. Es decir, como si utilizasemos un goto:

int i;
for (i = 0; i < 10; i++)
{
   Console.WriteLine("valor de i: {0}", i);
   if (i > 4)
   {
      goto salir;
   }
}
salir:
Console.WriteLine("Fin del bucle");
Console.WriteLine("valor de i: {0}", i);
 

¿Sorprendid@? Pues sí... la instrucción goto todavía existe en C#, y en otros muchos lenguajes... otra cosa es que, en general, su utilización sea contraproducente.

Pero volvamos al break. La pregunta del millón es: ¿Debemos utilizar ésta instrucción? No hay una respuesta rotunda. En general, no está bien visto utilizarla como norma, ni en el ámbito académico ni en el profesional. Básicamente, podemos apoyarnos en dos argumentos bastante sólidos.

En primer lugar, y desde un punto de vista meramente teórico, se puede argumentar que la instrucción break supone un salto incondicional, y por lo tanto, aquel algoritmo que la emplea, no sigue la programación estructurada. En el paradigma de la programación estructurada, todo algoritmo propio debe expresarse sólo con instrucciones repetitivas, secuenciales o condicionales. Desde los años 60 o 70, en los que las bondades de la programación estructurada quedaron claramente establecidas, se asume que para demostrar cualquier propiedad acerca de un algoritmo (por ejemplo, que haga lo que se le pide, o simplemente que funcione siempre), el algoritmo propuesto debe ser propio y estructurado. El teorema de Böhm-Jacopini nos garantiza que todo algoritmo propio puede expresarse con programación estructurada. Así pues ¿Para qué utilizar saltos incodicionales?

En segundo lugar, en un ámbito puramente práctico, es necesario tener en cuenta que los programas que desarrollemos no terminan su ciclo de vida cuando se ponen en producción: sufren cambios, modificaciones, ampliaciones... El hecho de salir de un bucle saltándose a la torera la condición del bucle provoca que cualquier programador que se enfrente a un código que no es suyo y que contenga saltos incodicionales (o incluso el mismo programador un tiempo después, cuando ya no tiene "fresco" el programa en la memoria) deba realizar un esfuerzo adicional por entender el código, ya que todos esperamos una salida natural del bucle cuando su condición no se cumple... y por supuesto, es muy complicado demostrar que el algoritmo o una modificación del algoritmo funciona. Así pues ¿por qué hacer nuestros algorimos más difíciles de entender? ¿Por qué complicar la demostración de que nuestros algoritmos son correctos?

Una instrucción break puede ser evitada siempre. Sin excepciones. Para ello, suele ser necesario ampliar la condición del bucle, contemplando la condición que hacía que se ejecutase la instrucción break.

En cuanto a la instrucción continue, el razonamiento es análogo a break. La instrucción continue hace que se salte al final del bucle, justo antes de repetir. No deja de ser un salto incondicional.

Por ejemplo, éste código

int i;
for (i = 0; i < 10; i++)
{
   if ((i >= 4) && (i <=7 ))
   {
      continue;
   } 
   Console.WriteLine("valor de i: {0}", i);
}
Console.WriteLine("Fin del bucle");
Console.WriteLine("valor de i: {0}", i);
 

que produce ésta salida:

valor de i: 0
valor de i: 1
valor de i: 2
valor de i: 3
valor de i: 8
valor de i: 9
Fin del bucle
valor de i: 10
 

es en realidad equivalente a

int i;
for (i = 0; i < 10; i++)
{
   if ((i >= 4) && (i <=7 ))
   {
      goto continuar;
   } 
   Console.WriteLine("valor de i: {0}", i);
continuar:
}
Console.WriteLine("Fin del bucle");
Console.WriteLine("valor de i: {0}", i);
 

Al igual que break, la instrucción continue puede evitarse siempre. Los motivos para no utilizarla son básicamente los mismos. Pero a diferencia de break, para evitar la instrucción continue, no suele ser necesario alterar la condición del bucle, basta con incluir algún tipo de condición en el interior del cuerpo del bucle.

En conclusión, desconozco los motivos por los cuales estas dos instrucciones (junto con el goto) todavía siguen existiendo en los lenguajes de programación de alto nivel. En general, suelen crear más problemas que beneficios. Quizá en un momento del pasado pudieron tener alguna importancia, cuando el hardware era caro, los procesadores lentos, los compiladores torpes y los programadores no estaban preparados. Quizá en ese tiempo, arañar unos microsegundos de ejecución utilizando un salto incondicional pudiera suponer alguna ventaja. En un entorno como el actual con procesadores superescalares External linksuperpipeline External link, compiladores optimizadores External link, treinta años de algoritmia detrás y programadores especializados han perdido el sentido que pudieran tener tiempo atrás. Las optimizaciones, cuando hablamos de alto nivel es mejor dejárselas al compilador. Recordemos que el último Premio Turing (2006) ha recaido en Fran Allen, por su trabajo en este campo.

 
Artículo siguiente→

Categorías

  • Ingeniería del software  ( 4 artículos )

    Acerca de la ingeniería del software y el ciclo de vida del software.

  • El programador elegante  ( 12 artículos )
    Una serie de artículos dedicados a buenas prácticas en programación
  • Opinión  ( 7 artículos )

    Artículos de opinión, no necesariamente fundamentada.

  • Básico  ( 12 artículos )

    Artículos básicos sobre temas básicos.

     

¿Quién está en línea?

 web tracker

Suscríbete

RSS feed Sindicación RSS

(¿Qué es la sindicación RSS?)


Suscribir por e-mail

¿Dónde estoy?

Estás en La tecla de ESCAPE, un sitio web personal en el que nos gusta hablar de algoritmos, informática, tecnología, ciencia, ingeniería, internet... y cualquier tontería que se nos ocurra. El punto de vista de nuestros artículos técnicos suele ser muy básico, así que a menudo adoptamos grandes simplificaciones. (Más...-Términos de uso)