A veces necesito bucles que necesitan un descanso como este:
for(int i=0;i<array.length;i++){
//some other code
if(condition){
break;
}
}
Me siento incómodo escribiendo
if(condition){
break;
}
porque consume 3 líneas de código. Y descubrí que el bucle se puede reescribir como:
↓
for(int i=0;i<array.length && !condition;i++){
//some other code
}
Entonces mi pregunta es, ¿es una buena práctica mover la condición al campo de condición para reducir líneas de códigos si es posible?
coding-style
loops
ocomfd
fuente
fuente
condition
en particular.for(int i=0;i<array.length && !condition;i++)
es relativamente poco común y puede ser pasado por alto por alguien que solo está leyendo el código; Este podría ser un buen caso de uso para un buclewhile
odo while
, que a menudo tiene múltiples condiciones de interrupción en la definición del bucle.Respuestas:
Esos dos ejemplos que dio no son funcionalmente equivalentes. En el original, la prueba de condición se realiza después de la sección "algún otro código", mientras que en la versión modificada, se realiza primero, al comienzo del cuerpo del bucle.
El código nunca debe reescribirse con el único propósito de reducir el número de líneas. Obviamente, es un buen bono cuando funciona de esa manera, pero nunca debe hacerse a expensas de la legibilidad o corrección.
fuente
No compro el argumento de que "consume 3 líneas de código" y, por lo tanto, es malo. Después de todo, podrías escribirlo como:
y solo consume una línea.
Si
if
aparece a la mitad del ciclo, por supuesto tiene que existir como una prueba separada. Sin embargo, si esta prueba aparece al final del bloque, ha creado un bucle que tiene una prueba continua en ambos extremos del bucle, posiblemente aumentando la complejidad del código. Sin embargo, tenga en cuenta que a veces laif (condition)
prueba solo puede tener sentido después de que se haya ejecutado el bloque.Pero suponiendo que ese no sea el caso, adoptando el otro enfoque:
las condiciones de salida se mantienen juntas, lo que puede simplificar las cosas (especialmente si " algún otro código " es largo).
No hay una respuesta correcta aquí, por supuesto. Por lo tanto, tenga en cuenta las expresiones idiomáticas del idioma, cuáles son las convenciones de codificación de su equipo, etc. Pero, en general, adoptaría el enfoque de prueba única cuando tenga sentido funcional hacerlo.
fuente
Este tipo de pregunta ha provocado un debate casi tan largo como la programación. Para lanzar mi sombrero al ring, iría por la versión con la
break
condición y he aquí por qué (para este caso específico ):El
for
bucle está allí para especificar los valores de iteración en el bucle. Codificar la condición de ruptura dentro de eso solo enturbia la lógica de la OMI.Tener un elemento separado
break
deja en claro que durante el procesamiento normal, los valores son los especificados en elfor
bucle y el procesamiento debe continuar, excepto donde entra la condición.Como antecedentes, comencé a codificar a
break
, luego puse la condición en elfor
bucle durante años (bajo la dirección de un programador excepcional) y luego volví albreak
estilo porque se sentía mucho más limpio (y era el estilo predominante en los diversos tomos de código que estaba consumiendo).Es otra de esas guerras santas al final del día: algunos dicen que nunca debes salir de un ciclo artificialmente, de lo contrario no es un ciclo real. Haz lo que sientas que es legible (tanto para ti como para los demás). Si lo tuyo es reducir las pulsaciones de teclas, practica golf de código los fines de semana: cerveza opcional.
fuente
for
bucles se usan cuando se conoce el número de iteraciones (por ejemplo, cuando no hay una condición de interrupción pero el final de la matriz / lista) ywhile
cuando no. Este parece ser el caso de unwhile
bucle. Si la legibilidad es la preocupación,idx+=1
es mucho más limpio leer dentro de un bucle que unif/else
bloquefor(int i=0; i<something;i++)
bucles que supongo que la mitad de los desarrolladores realmente no recuerdan que losfor
bucles se pueden usar de manera diferente y, por lo tanto, tienen dificultades para comprender la&&condition
parte.for(;;)
...for
los bucles son para la iteración sobre algo 1 : no son solo lol-vamos a sacar algunas cosas al azar del cuerpo y ponerlas en el encabezado del bucle: las tres expresiones tienen muy significados específicos:La idea es separar el manejo de la iteración ( cómo iterar) de la lógica dentro del bucle ( qué hacer en cada iteración). Muchos idiomas generalmente tienen un ciclo para cada uno que lo libera de los detalles de la iteración, pero incluso si su idioma no tiene esa construcción, o si no se puede usar en su escenario, aún debe limitar el encabezado del ciclo a la iteración de manejo.
Entonces, debe preguntarse: ¿es su condición sobre el manejo de la iteración o sobre la lógica dentro del bucle? Lo más probable es que se trata de la lógica dentro del bucle, por lo que debe verificarse dentro del bucle en lugar de en el encabezado.
1 A diferencia de otros bucles, que están "esperando" que algo suceda. Un
for
/foreach
loop debe tener el concepto de una "lista" de elementos para iterar, incluso si esa lista es perezosa o infinita o abstracta.fuente
someFunction(array[i])
. Ahora ambas partes de la condición son sobre lo que estás iterando, y tendría sentido combinarlas con&&
el encabezado del bucle.for
bucles en el fondo son contadores, no bucles en una lista, y esto es compatible con la sintaxis defor
los idiomas anteriores (estos idiomas a menudo tenían unafor i = 1 to 10 step 2
sintaxis y elstep
comando, incluso permitiendo un valor inicial que no es el índice del primero elemento: insinúa un contexto numérico, no un contexto de lista). El único caso de uso que creo que admitefor
bucles, ya que solo iterar sobre una lista es paralelizar, y eso requiere una sintaxis explícita ahora de todos modos para no romper el código haciendo, por ejemplo, una ordenación.Recomiendo usar la versión con
if (condition)
. Es más legible y más fácil de depurar. Escribir 3 líneas adicionales de código no te romperá los dedos, pero facilitará que la siguiente persona entienda tu código.fuente
naming things
para entender lo que está sucediendo y cuándo se cumple la condición de ruptura.Si está iterando sobre una colección donde se deben omitir ciertos elementos, le recomiendo una nueva opción:
Tanto Java como C # hacen que esto sea relativamente trivial. No me sorprendería si C ++ tuviera una forma de hacer un iterador elegante para omitir ciertos elementos que no se aplican. Pero esta es realmente una opción si su idioma de elección lo admite, y la razón por la que está utilizando
break
es porque hay condiciones sobre si procesa un elemento o no.De lo contrario, hay una muy buena razón para que su condición forme parte del ciclo for, suponiendo que su evaluación inicial sea correcta.
He trabajado en el código donde su bucle for toma unos cientos de líneas con varios condicionales y algunas matemáticas complejas que están sucediendo allí. Los problemas que encuentra con esto son:
break
los comandos enterrados en la lógica son difíciles de encontrar y a veces sorprendentesEn esa situación, recomiendo las siguientes pautas en orden de preferencia:
break
posiblebreak
en la parte superior del bucle si es posibleEstas pautas siempre están sujetas a la corrección de su código. Elija la opción que mejor represente la intención y mejore la claridad de su código.
fuente
continue
declaraciones, pero no veo cómo ayudan muchobreak
.takeWhile
filtro puede reemplazarbreak
declaraciones. Si tiene uno, Java, por ejemplo, solo los obtiene en Jave 9 (no es que sea tan difícil implementarlo usted mismo)Recomiendo encarecidamente adoptar el enfoque de menor sorpresa a menos que obtenga un beneficio significativo al hacer lo contrario.
Las personas no leen todas las letras cuando leen una palabra, y no leen todas las palabras cuando leen un libro; si son expertos en la lectura, miran los contornos de las palabras y oraciones y dejan que su cerebro complete el resto .
Entonces, es probable que el desarrollador ocasional suponga que esto es solo un estándar para el bucle y ni siquiera lo mire:
Si quiere usar ese estilo independientemente, le recomiendo cambiar las partes
for(int i=0;i<
y;i++)
que le digan al cerebro del lector que este es un estándar para el bucle.Otra razón para ir con
if
-break
es que no siempre se puede utilizar el enfoque con elfor
innecesaria cualquier condición. Usted tiene que utilizarif
-break
cuando la condición de rotura es demasiado complejo para ocultar dentro de unafor
declaración, o se basa en variables que sólo se puede acceder en el interior delfor
bucle.Así que si usted decide ir con
if
-break
, que está cubierto. Pero si usted decide ir confor
-condiciones, usted tiene que utilizar una mezcla deif
-break
yfor
-condiciones. Para ser coherente, que tendrá que mover las condiciones de ida y vuelta entre lasfor
-condiciones yif
-break
cada vez que cambian las condiciones.fuente
Su transformación está asumiendo que todo lo que
condition
se evalúa atrue
medida que ingresa al bucle. No podemos comentar la corrección de eso en este caso porque no está definido.Después de tener éxito en "reducir las líneas de código" aquí, puede continuar mirando
y aplicar la misma transformación, llegando a
Lo cual es una transformación no válida, como ahora haces incondicionalmente
further code
donde antes no lo hacías.Un esquema de transformación mucho más seguro es extraer
some other code
y evaluarcondition
una función separadafuente
TL; DR Haz lo que se lea mejor en tu circunstancia particular
Tomemos este ejemplo:
En este caso, no queremos que se ejecute ninguno de los códigos del bucle for si
something
es verdadero, por lo quesomething
es razonable mover la prueba al campo de condición.Por otra parte, dependiendo de si
something
se puede establecertrue
antes del ciclo, pero no dentro de él, esto podría ofrecer más claridad:Ahora imagina esto:
Estamos enviando un mensaje muy claro allí. Si
something
se cumple mientras se procesa la matriz, abandone toda la operación en este punto. Para mover el cheque al campo de condición que necesita hacer:Podría decirse que el "mensaje" se ha enlodado, y estamos verificando la condición de falla en dos lugares: ¿qué sucede si la condición de falla cambia y olvidamos uno de esos lugares?
Por supuesto, hay muchas más formas diferentes para un bucle y una condición, todas con sus propios matices.
Escriba el código para que se lea bien (esto es obviamente algo subjetivo) y de manera concisa. Fuera de un conjunto draconiano de pautas de codificación, todas las "reglas" tienen excepciones. Escriba lo que siente que expresa mejor la toma de decisiones y minimice las posibilidades de errores futuros.
fuente
Si bien puede ser atractivo porque ve todas las condiciones en el encabezado del bucle y
break
puede ser confuso dentro de bloques grandes, unfor
bucle es un patrón en el que la mayoría de los programadores esperan bucles en algún rango.Especialmente porque lo hace, agregar una condición de descanso adicional puede causar confusión y es más difícil ver si es funcionalmente equivalente.
A menudo, una buena alternativa es usar un bucle
while
odo {} while
que verifique ambas condiciones, suponiendo que su matriz tenga al menos un elemento.Al usar un bucle que solo verifica una condición y no ejecuta código desde el encabezado del bucle, deja muy claro cuándo se verifica la condición y cuál es la condición real y cuál es el código con efectos secundarios.
fuente
for(...; i <= n; ...)
) hace que el código sea más difícil de leer porque tengo detenerse y pensar en lo que está sucediendo aquí y podría pasar por alto la condición en la primera pasada porque no espero que esté allí. Para mí, unfor
bucle implica que está recorriendo un rango, si hay una condición de salida especial, debe hacerse explícito con unif
, o puede usar awhile
.Esto es malo, ya que el código está destinado a ser leído por humanos: los
for
bucles no idiomáticos a menudo son confusos de leer, lo que significa que es más probable que los errores se escondan aquí, pero el código original pudo haber sido posible mientras se mantenía ambos Corto y legible.Si lo que desea es encontrar un valor en una matriz (el ejemplo de código proporcionado es algo genérico, pero también puede ser este patrón), puede intentar explícitamente utilizar una función proporcionada por un lenguaje de programación específicamente para ese propósito. Por ejemplo (pseudocódigo, como no se especificó un lenguaje de programación, las soluciones varían según un lenguaje en particular).
Esto debería acortar notablemente la solución y simplificarla, ya que su código dice específicamente lo que necesita.
fuente
Pocas razones en mi opinión que dice, no deberías.
do...while
bucle (nowhile
) ya que la condición se verifica después de una ejecución de código.Pero además de eso, considera esto,
Ahora, ¿realmente puedes lograrlo agregando estas condiciones a esa
for
condición?fuente
Creo que eliminarlo
break
puede ser una buena idea, pero no para guardar líneas de código.La ventaja de escribir sin él
break
es que la condición posterior del bucle es obvia y explícita. Cuando finaliza el ciclo y ejecuta la siguiente línea del programa, su condición de cicloi < array.length && !condition
debe haber sido falsa. Por lo tanto,i
era mayor o igual que la longitud de su matriz, ocondition
es cierto.En la versión con
break
, hay una trampa oculta. La condición del bucle dice que el bucle termina cuando ha ejecutado algún otro código para cada índice de matriz válido, pero de hecho hay unabreak
declaración que podría terminar el bucle antes de eso, y no lo verá a menos que revise el código del bucle. muy cuidadosamente. Y los analizadores estáticos automáticos, incluida la optimización de compiladores, también podrían tener problemas para deducir cuáles son las condiciones posteriores del bucle.Esta fue la razón original por la que Edgar Dijkstra escribió "Goto Considerado Dañino". No fue una cuestión de estilo: romper un círculo hace que sea difícil razonar formalmente sobre el estado del programa. He escrito muchas
break;
declaraciones en mi vida, y una vez como adulto, incluso escribí ungoto
(para salir de múltiples niveles de un ciclo interno crítico para el rendimiento y luego continuar con otra rama del árbol de búsqueda). Sin embargo, es mucho más probable que escriba unareturn
declaración condicional desde un bucle (que nunca ejecuta el código después del bucle y, por lo tanto, no puede acumular sus condiciones posteriores) que abreak
.Posdata
De hecho, refactorizar el código para dar el mismo comportamiento podría necesitar más líneas de código. Su refactorización podría ser válida para algún otro código en particular o si podemos demostrar que
condition
comenzará en falso. Pero su ejemplo es equivalente en el caso general a:Si algún otro código no es de una sola línea, puede moverlo a una función para que no se repita, y casi ha refactorizado su bucle en una función recursiva de cola.
Sin embargo, reconozco que este no era el punto principal de su pregunta, y lo mantenía simple.
fuente
break
declaración, entonces sabes cuál es la condición del bucle y que el bucle se detiene cuando esa condición es falsa. Si hay unbreak
? Luego, hay varias formas en que el ciclo podría terminar, y en el caso general, descubrir cuándo una de ellas podría detener el ciclo es, literalmente, resolver el problema de detención. En la práctica, mi mayor preocupación es que el bucle parece que hace una cosa, pero en realidad, quien escribió el código después del bucle pasó por alto un caso marginal oculto en su lógica compleja. Las cosas en la condición de bucle son difíciles de perder.Sí, pero su sintaxis no es convencional y, por lo tanto, es mala (tm)
Esperemos que tu idioma sea compatible con algo como
fuente
while
enfatiza el monstruo en el código, la excepción oculta en el código de rutina / mundano. La lógica de negocios es frontal y central, la mecánica de bucle está subsumida. Evita la reacción de "espera un minuto ..." a lafor
alternativa del bucle. Esta respuesta soluciona el problema. Absolutamente voto.Si le preocupa que una
for
declaración demasiado compleja sea difícil de leer, definitivamente es una preocupación válida. El desperdicio de espacio vertical también es un problema (aunque menos crítico).(Personalmente, no me gusta la regla de que las
if
declaraciones siempre deben tener llaves, que es en gran parte la causa del desperdicio de espacio vertical aquí. Tenga en cuenta que el problema es desperdiciar espacio vertical. Usar espacio vertical con líneas significativas no debería ser un problema).Una opción es dividirlo en varias líneas. Esto es definitivamente lo que debe hacer si está usando
for
declaraciones realmente complejas , con múltiples variables y condiciones. (Esto es para mí un mejor uso del espacio vertical, dando tantas líneas como sea posible algo significativo).Un mejor enfoque podría ser tratar de usar una forma más declarativa y menos imperativa. Esto variará según el idioma, o puede que necesite escribir sus propias funciones para habilitar este tipo de cosas. También depende de lo que
condition
realmente es. Presumiblemente, debe poder cambiar de alguna manera, dependiendo de lo que esté en la matriz.fuente
for
declaración compleja o inusual en varias líneas es la mejor idea en toda esta discusiónUna cosa que se olvidó: cuando rompo un bucle (no hago todas las iteraciones posibles, sin importar cómo se implemente), generalmente es el caso de que no solo quiero salir del bucle, también querré saber por qué sucedió esto . Por ejemplo, si busco un elemento X, no solo rompo el ciclo, también quiero saber si se encontró X y dónde está.
En esa situación, tener una condición fuera del circuito es bastante natural. Entonces empiezo con
y en el bucle escribiré
con el bucle for
Ahora comprobar la condición en el bucle es bastante natural. Si hay una declaración de "interrupción" depende de si hay más procesamiento en el ciclo que desea evitar. Si se necesita algún procesamiento y otro no, es posible que tenga algo como
en algún lugar de tu circuito.
fuente