Procesamiento de bucles utilizando continue

De la misma manera que break se utiliza en PHP para terminar la ejecución de las estructuras de control for, foreach, while, do-while o switch mientras se está iterando sobre ellas, la declaración continue se utiliza para obviar el resto del código y proceder a la siguiente iteración.

Supongamos que tenemos un array $data que contiene los id de los items de nuestro catálogo y en determinado momento necesitamos agregar cierta funcionalidad a nuestra aplicación que sólo se ejecute si se cumple determinada condición:


<?php
$data = array(1, 2, 7, 106, 1024, 8953);
foreach ($data as $id){
    if (!$info getItemInfo($id)){
        continue;
    }
    /*
     * [...]
     *   Resto de código extenso (o no) dentro del bucle.
     * [...]
     */
}
?>

Utilizando continue el código contenido dentro del bucle va a obviar (o saltarse) los elementos del nuestro catálogo de los cuales no se pueda obtener información (getItemInfo() retorna FALSE), pero va a continuar procesando el resto hasta terminar de recorrer el array.

Comentarios:

  1. Existen varias construcciones en distintos lenguajes que conviene pensar dos veces antes de usarla.
    Ésta es una de ellas... ¿qué ventajas tiene con respecto a usar un else (en tu ejemplo al menos)?
    Ciertamente lo hace menos legible. Con el break, si estás mirando el "resto del código extenso" no tenés clara indicación inmediata de que eso se ejecuta en el caso de que no se cumpla una condición... de la otra manera, por lo menos está incluída en un bloque de código (algunos editores te permite colapsarlos y es un poco más visible).
    No digo que haya alguna situación en la que valga la pena, pero break, continue y otros son (para mí) definitivamente un language smell...

    Saludos,

    nachokb

    Enviado por nachokb el 13/03/2008 07:13:51 (#).

  2. Habría que hacer unos test para ver que opcion rinde mas (if/else o break/continue)

    Sobre lo que dijo nachokb, algo de razon tiene, a vista de pajaro por ahi esas instrucciones te las podes comer dobladas, pero como todo, siempre es necesario usar la herramienta correcta.

    Enviado por Babblo el 13/03/2008 07:13:36 (#).

  3. @nachokb: Te parece que lo hace menos legible? De movida te ahorrás una tabulación (si tenés muchos if anidados la diferencia sería hasta agradecida).

    Te doy otro ejemplo, esta vez con break. Supongamos que tenés que recorrer un array manualmente para encontrar ciertos datos de los cuales sólo necesitás 10. Sin break la única manera que se me ocurre de hacer ésto es usando return dentro de una función que contienga la estructura de bucle. Y ojo, porque el array puede tener 1 solo elemento o 1 millón.

    A mi particularmente, me parece que agregar una sola función para usarla en un sólo lugar no es algo demasiado correcto.

    Sobre el code folding, no es algo a lo que me haya podido acostumbrar. Principalmente porque la interfaz gráfica llora cada vez que lo uso y este llanto me pone los pelos de punta :P. Otro motivo es porque más de una vez me descajetó código y eso también me saca :P. ¿Nunca hicieron Ctrl+T en UltraEdit?

    Enviado por Juan el 13/03/2008 08:13:15 (#).

  4. Hmm... nunca usé un continue, ahora que lo pienso... aunque no porque me parezca malo, simplemente porque nunca se dio la situación...

    Depende del caso; si, como vos decís, te salva de indentación excesiva, groso... algo que no me gusta de C (¡herejía!) es que no me deja hacer break/continues contados; por poner como ejemplo un Tetris que escribí: cuando reviso una línea, podría ahorrarme un par de ifs si hiciera un "continue 2" (saliendo del bucle de columna para ir al próximo de fila). En su lugar tengo que usar breaks e ifs...

    Enviado por Tordek el 14/03/2008 01:14:36 (#).

  5. En la vieja escuela de la programación estaba mal visto usar break o continue (si es que el lenguaje del momento lo soportaba), y se supone que toda estructura que use break o continue puede ser resuelta de otra manera, en teoría más óptima.

    Enviado por IgnacioMarcos el 14/03/2008 08:14:07 (#).

  6. No es mi intención escribir un "continue considered harmful", pero algo más diré (no me puedo resistir je!).

    @babblo: por lo general no enfocaría una decisión así en un tema de performance, ya que (y acá no puedo respaldar mucho lo que digo) me parece que en ambos casos existen iguales oportunidades de optimización para el compilador... y además, salvo que REALMENTE sea necesario, prefiero enfocarme en la legibilidad... dijo Knuth "premature optimization is the root of all evil".

    @juan: Me parece que sí es más legible con el if. Si hay muchos if's anidados, de movida algo (mucho) ya hay mal (code smell). Y aún en ese caso prefiero que sea explícito... ahorrar un tab no lo hace más legible, sólo oculta un problema que no va a dejar de existir por que lo oculte...

    El ejemplo que contás ilustra particularmente que break y continue son un language smell [1], y cito "...occurs due to the inability of the language to express the concept cleanly...". Ciertamente si vos querés manipular una lista de esa manera, el conjunto de abstracciones que provee por ejemplo Smalltalk (detect, select, etc.) son mucho más poderosas que "recorrer" elementos y fijarse cuándo cortar o no (para lo que necesitás conocer demasiados detalles sobre la estructura en lugar de concentrarte en lo que querés obtener).

    Está claro que si el lenguaje ni siquiera soporta closures, no te quedan muchas opciones y hasta tiene sentido recurrir a break / continue (por ello digo que es un language smell). No grito "sacrilegio" cada vez que alguien usa un continue o un break (o, incluso, el abominable switch)... Simplemente intento concientizar que no está bueno y qué problemas trae (más allá de que en el caso particular dada las circunstancias, esté bien usarlo). Pensalo siempre no como cuán fácil o difícil es escribirlo, sino como cuán fácil o difícil es leerlo.

    > A mi particularmente, me parece que agregar una sola función para usarla
    > en un sólo lugar no es algo demasiado correcto.

    ¿Y tener ese pedazo de comportamiento disperso sí es "demasiado correcto"? Me parece que el problema no es crear la función, sino la falta de abstracción, que hace que esa función sólo sirva en un único lugar. 99.999% de probabilidades que lo que está expresado en ese código sea en su mayoría factorizable, y lo que aporta información (lo que marca la intención del que lo escribió) sea una minoría escondida en los detalles... y todo eso hace que leerlo (descifrar la intención del que escribió eso) se transforme en buscar la aguja escondida en un pajar de código boiler plate... la repetición es la plaga.

    Sobre el code folding, lo dije como un premio consuelo (o sea, tener muchos if's ya está mal y punto), no le doy mucha bola. Dicho eso, si el UltraEdit te rompió código con algo que debe ser no intrusivo, ¡MUERTE al UltraEdit jeje!.

    PD: no se resaltar los "if", "break" como Juan :(

    Y bueno, al final se hizo largo :(. ¡Pero igual me gusta la pequeña discusión que surgió de mi comentario!.

    Nacho

    [1] http://c2.com/cgi/wiki?LanguageSmell

    Enviado por nachokb el 14/03/2008 02:14:13 (#).

  7. Habia usado el break pero no el continue, no la tenia a esa.
    Yo creo que codigo legible se puede escribir usando continue's, if's, otro's.
    La calidad del codigo no esta dada por si usamos una estructura de control u otra.
    Por otra parte quiero resaltar que estas estructuras de control "prohibidas" son muy utiles en ciertos casos. Un ejemplo podria ser en lenguaje C con el goto, que en sistemas embebidos ahorra mucho codigo y tamaño en flash.
    Todo tiene su utilidad y solamente hay que saber bien donde/cuando/como aplicar las bondades (o no) que te provee un lenguaje.

    Saludos

    Enviado por Coke el 14/03/2008 03:14:45 (#).

  8. @nachokb: honestamente no conozco demasiados lenguajes como para extender más la conversación. Si bien en el fondo siento que tenés razón, también es cierto lo que dice Coke: Todo tiene su utilidad y solamente hay que saber bien donde/cuando/como aplicar las bondades (o no) que te provee un lenguaje.

    La verdad que sí, se armó un thread muy interesante en base a tu punto de vista. Te agradezco por eso ;)

    PD: para resaltar el código podés utilizar el elemento HTML <code>. No filtro los tags de los comentarios a menos que vea algo raro.

    Enviado por Juan el 17/03/2008 08:17:08 (#).