Considere el siguiente código:
public void doSomething(int input)
{
while(true)
{
TransformInSomeWay(input);
if(ProcessingComplete(input))
break;
DoSomethingElseTo(input);
}
}
Suponga que este proceso implica un número finito pero dependiente de entrada de pasos; el bucle está diseñado para terminar por sí solo como resultado del algoritmo, y no está diseñado para ejecutarse indefinidamente (hasta que sea cancelado por un evento externo). Debido a que la prueba para ver si el ciclo debe finalizar se encuentra en el medio de un conjunto lógico de pasos, el ciclo while en sí mismo actualmente no verifica nada significativo; la verificación se realiza en el lugar "apropiado" dentro del algoritmo conceptual.
Me dijeron que este es un código incorrecto, porque es más propenso a errores debido a que la estructura de bucle no verifica la condición de finalización. Es más difícil descubrir cómo saldría del bucle, y podría invitar a los errores, ya que la condición de ruptura podría omitirse u omitirse accidentalmente en futuros cambios.
Ahora, el código podría estructurarse de la siguiente manera:
public void doSomething(int input)
{
TransformInSomeWay(input);
while(!ProcessingComplete(input))
{
DoSomethingElseTo(input);
TransformInSomeWay(input);
}
}
Sin embargo, esto duplica una llamada a un método en código, violando DRY; si TransformInSomeWay
luego se reemplazara con algún otro método, ambas llamadas tendrían que ser encontradas y cambiadas (y el hecho de que haya dos puede ser menos obvio en un código más complejo).
También puedes escribirlo como:
public void doSomething(int input)
{
var complete = false;
while(!complete)
{
TransformInSomeWay(input);
complete = ProcessingComplete(input);
if(!complete)
{
DoSomethingElseTo(input);
}
}
}
... pero ahora tiene una variable cuyo único propósito es cambiar la verificación de condición a la estructura de bucle, y también debe verificarse varias veces para proporcionar el mismo comportamiento que la lógica original.
Por mi parte, digo que dado el algoritmo que este código implementa en el mundo real, el código original es el más legible. Si lo estuviera haciendo usted mismo, esta es la forma en que lo pensaría, por lo que sería intuitivo para las personas familiarizadas con el algoritmo.
Entonces, ¿cuál es "mejor"? ¿Es mejor dar la responsabilidad de la verificación de condiciones al ciclo while estructurando la lógica alrededor del ciclo? ¿O es mejor estructurar la lógica de una manera "natural" como lo indican los requisitos o una descripción conceptual del algoritmo, aunque eso puede significar pasar por alto las capacidades integradas del bucle?
do ... until
construcción también es útil para este tipo de bucles ya que no tienen que estar "cebados".Respuestas:
Quédate con tu primera solución. Los bucles pueden involucrarse mucho y uno o más descansos limpios pueden ser mucho más fáciles para usted, cualquier otra persona que vea su código, el optimizador y el rendimiento del programa que elabora declaraciones if y variables agregadas. Mi enfoque habitual es configurar un bucle con algo como "while (verdadero)" y obtener la mejor codificación que pueda. A menudo puedo y luego reemplazo las interrupciones con un control de bucle estándar; La mayoría de los bucles son bastante simples, después de todo. La estructura de bucle debe verificar la condición de finalización por las razones que menciona, pero no a costa de agregar nuevas variables enteras, agregar sentencias if y repetir código, todo lo cual es aún más propenso a errores.
fuente
Es solo un problema significativo si el cuerpo del bucle no es trivial. Si el cuerpo es tan pequeño, entonces analizarlo de esta manera es trivial y no es un problema en absoluto.
fuente
Tengo problemas para encontrar las otras soluciones mejor que la que tiene un descanso. Bueno, prefiero la forma Ada que permite hacer
pero la solución de ruptura es la representación más limpia.
Mi punto de vista es que cuando falta una estructura de control, la solución más limpia es emularla con otras estructuras de control, sin utilizar el flujo de datos. (Y de manera similar, cuando tengo un problema de flujo de datos para preferir soluciones de flujo de datos puro al que involucra estructuras de control *).
No se equivoque, la discusión no tendría lugar si la dificultad no fuera la misma: la condición es la misma y está presente en el mismo lugar.
Cual de
y
hacer mejor la estructura prevista? Voy a votar por el primero, no tienes que verificar que las condiciones coincidan. (Pero mira mi sangría).
fuente
while (verdadero) y break es un idioma común. Es la forma canónica de implementar bucles de salida media en lenguajes tipo C. Agregar una variable para almacenar la condición de salida y un if () alrededor de la segunda mitad del ciclo es una alternativa razonable. Algunas tiendas pueden estandarizarse oficialmente en una u otra, pero ninguna es superior; son equivalentes
Un buen programador que trabaje en estos idiomas debería ser capaz de saber lo que está sucediendo de un vistazo si ve cualquiera de ellos. Podría ser una buena pregunta para la entrevista; entregarle a alguien dos bucles, uno usando cada idioma, y preguntarles cuál es la diferencia (respuesta correcta: "nada", con quizás una adición de "pero habitualmente uso ESO").
fuente
Sus alternativas no son tan malas como puede pensar. Un buen código debería:
Indique claramente con buenos nombres / comentarios de variables bajo qué condiciones se debe terminar el ciclo. (La condición de ruptura no debe ocultarse)
Indique claramente cuál es el orden de las operaciones. Aquí es donde poner la tercera operación opcional (
DoSomethingElseTo(input)
) dentro del if es una buena idea.Dicho esto, es fácil dejar que los instintos perfeccionistas y pulidores de latón consuman mucho tiempo. Simplemente modificaría el if como se mencionó anteriormente; comenta el código y sigue adelante.
fuente
La gente dice que es una mala práctica usar
while (true)
, y muchas veces tienen razón. Si tuwhile
declaración contiene muchos códigos complicados y no está claro cuándo está rompiendo si, entonces queda un código difícil de mantener y un error simple podría causar un bucle infinito.En su ejemplo, es correcto de usar
while(true)
porque su código es claro y fácil de entender. No tiene sentido crear código ineficiente y difícil de leer, simplemente porque algunas personas consideran que siempre es una mala práctica usarlowhile(true)
.Me enfrenté a un problema similar:
El uso
do ... while(true)
evitaisset($array][$key]
innecesariamente ser llamado dos veces, el código es más corto, más limpio y más fácil de leer. No hay absolutamente ningún riesgo de que se introduzca un error de bucle infinitoelse break;
al final.Es bueno seguir las buenas prácticas y evitar las malas prácticas, pero siempre hay excepciones y es importante mantener una mente abierta y darse cuenta de esas excepciones.
fuente
Si un flujo de control particular se expresa naturalmente como una declaración de interrupción, esencialmente nunca es una mejor opción utilizar otros mecanismos de control de flujo para emular una declaración de interrupción.
(tenga en cuenta que esto incluye desenrollar parcialmente el bucle y deslizar el cuerpo del bucle hacia abajo para que el bucle comience coincida con la prueba condicional)
Si puede reorganizar su ciclo para que el flujo de control se exprese naturalmente al tener una verificación condicional al comienzo del ciclo, genial. Incluso podría valer la pena pasar un tiempo pensando si eso es posible. Pero no es así, no intentes colocar una clavija cuadrada en un agujero redondo.
fuente
También podrías ir con esto:
O menos confuso:
fuente
Cuando la complejidad de la lógica se vuelve difícil de manejar, el uso de un bucle sin límites con interrupciones de medio bucle para el control de flujo realmente tiene más sentido. Tengo un proyecto con un código similar al siguiente. (Observe la excepción al final del ciclo).
Para hacer esta lógica sin romper el bucle sin límites, terminaría con algo como lo siguiente:
Entonces la excepción ahora se lanza en un método auxiliar. También tiene bastante
if ... else
anidamiento. No estoy satisfecho con este enfoque. Por lo tanto, creo que el primer patrón es el mejor.fuente