A menudo escribí este tipo de función en ambos formatos, y me preguntaba si se prefiere un formato sobre otro y por qué.
public void SomeFunction(bool someCondition)
{
if (someCondition)
{
// Do Something
}
}
o
public void SomeFunction(bool someCondition)
{
if (!someCondition)
return;
// Do Something
}
Por lo general, codifico con el primero, ya que esa es la forma en que funciona mi cerebro durante la codificación, aunque creo que prefiero el segundo, ya que se ocupa de cualquier manejo de errores de inmediato y me resulta más fácil de leer
Respuestas:
Prefiero el segundo estilo. Primero, elimine los casos no válidos, ya sea simplemente saliendo o generando excepciones según corresponda, coloque una línea en blanco allí, luego agregue el cuerpo "real" del método. Me resulta más fácil de leer.
fuente
Definitivamente el último. El primero no se ve mal en este momento, pero cuando obtienes un código más complejo, no puedo imaginar que alguien piense esto:
es más legible que
Admito completamente que nunca entendí la ventaja de los puntos de salida individuales.
fuente
return value;
ayuda!?! Entonces uno tiene que cazar media docenavalue = ...
, con la desventaja de que nunca está seguro de que el valor no se cambiará entre esta asignación y el rendimiento final. Al menos un retorno inmediato es claro que ya nada cambiará el resultado.Depende : en general, no voy a salir de mi camino para tratar de mover un montón de código para romper la función antes, el compilador generalmente se encargará de eso por mí. Sin embargo, dicho esto, si hay algunos parámetros básicos en la parte superior que necesito y no puedo continuar de otra manera, comenzaré temprano. Del mismo modo, si una condición genera un
if
bloque gigante en la función, también tendré una ruptura temprana como resultado de eso.Dicho esto, sin embargo, si una función requiere algunos datos cuando se llama, generalmente voy a lanzar una excepción (ver ejemplo) en lugar de simplemente regresar.
fuente
Prefiero el regreso temprano.
Si tiene un punto de entrada y un punto de salida, siempre tiene que rastrear todo el código en su cabeza hasta el punto de salida (nunca se sabe si algún otro código de abajo hace algo más al resultado, por lo que tiene que rastrearlo hasta que exista). Usted no hace eso, qué rama determina el resultado final. Esto es difícil de seguir.
Con una entrada y múltiples existen, regresa cuando tiene su resultado y no se molesta en rastrearlo para ver que nadie le hace nada más (porque no habrá nada más desde que regresó). Es como dividir el cuerpo del método en más pasos, cada uno con la posibilidad de devolver el resultado o dejar que el siguiente paso pruebe su suerte.
fuente
En la programación en C, donde tiene que limpiar manualmente, hay mucho que decir para el retorno de un punto. Incluso si no hay necesidad en este momento de limpiar algo, alguien podría editar su función, asignar algo y necesitar limpiarlo antes de regresar. Si eso sucede, será un trabajo de pesadilla revisar todas las declaraciones de devolución.
En la programación C ++ tienes destructores e incluso ahora guardias de salida de alcance. Todo esto debe estar aquí para garantizar que el código sea seguro para excepciones en primer lugar, por lo que el código está bien protegido contra la salida anticipada y, por lo tanto, hacerlo no tiene un inconveniente lógico y es puramente un problema de estilo.
No tengo suficiente conocimiento sobre Java, si se llamará "finalmente" al código de bloque y si los finalizadores pueden manejar la situación de la necesidad de garantizar que algo suceda.
C # Ciertamente no puedo responder.
El lenguaje D le brinda protectores de salida de alcance incorporados y, por lo tanto, está bien preparado para la salida temprana y, por lo tanto, no debe presentar un problema que no sea el estilo.
Las funciones, por supuesto, no deberían ser tan largas en primer lugar, y si tiene una gran declaración de cambio, su código probablemente también esté mal factorizado.
fuente
goto
y, posiblemente, un retorno de dos puntos. Ejemplo (el formato de código no es posible en los comentarios):foo() { init(); if (bad) goto err; bar(); if (bad) goto err; baz(); return 0; err: cleanup(); return 1; }
Regresos anticipados para ganar. Pueden parecer feos, pero mucho menos feos que los grandes
if
envoltorios, especialmente si hay varias condiciones para verificar.fuente
Yo uso ambos.
Si
DoSomething
hay 3-5 líneas de código, entonces el código se ve hermoso usando el primer método de formateo.Pero si tiene muchas más líneas que eso, entonces prefiero el segundo formato. No me gusta cuando los corchetes de apertura y cierre no están en la misma pantalla.
fuente
Una razón clásica para la entrada única-salida única es que, de lo contrario, la semántica formal se vuelve indescriptiblemente fea (la misma razón por la que GOTO se consideró perjudicial).
Dicho de otra manera, es más fácil razonar cuándo su software saldrá de la rutina si solo tiene 1 retorno. Lo cual también es un argumento contra las excepciones.
Por lo general, minimizo el enfoque de retorno temprano.
fuente
Personalmente, prefiero hacer comprobaciones de condición de aprobado / reprobado al principio. Eso me permite agrupar la mayoría de las fallas más comunes en la parte superior de la función con el resto de la lógica a seguir.
fuente
Depende.
Regreso anticipado si hay alguna condición obvia de callejón sin salida para verificar de inmediato que haría que ejecutar el resto de la función no tenga sentido. *
Establezca Retval + retorno único si la función es más compleja y de lo contrario podría tener múltiples puntos de salida (problema de legibilidad).
* Esto a menudo puede indicar un problema de diseño. Si encuentra que muchos de sus métodos necesitan verificar algún estado externo / paramater o similar antes de ejecutar el resto del código, es probable que sea algo que debe manejar la persona que llama.
fuente
Fred
la ventana ya está activadaFred
, y establecer el nombre del control en su estado actual forzaría un redibujo (que, aunque potencialmente útil en algunos casos, podría ser molesto en el que está a la mano), sería perfectamente razonable tener la salida anticipada del método set-name si los nombres antiguos y nuevos coinciden.Use un If
En el libro de Don Knuth sobre GOTO, leí que da una razón para que siempre tenga la condición más probable primero en una declaración if. Bajo el supuesto de que esta sigue siendo una idea razonable (y no por pura consideración de la velocidad de la era). Diría que los retornos tempranos no son una buena práctica de programación, especialmente teniendo en cuenta el hecho de que la mayoría de las veces no se usan para el manejo de errores, a menos que su código tenga más probabilidades de fallar que no fallar :-)
Si sigues el consejo anterior, deberías colocar ese retorno en la parte inferior de la función, y entonces es posible que ni siquiera lo llames un retorno allí, solo configura el código de error y devuelve dos líneas por lo tanto. De este modo logrando la entrada 1 salida 1 ideal.
Delphi Específico ...
Creo que esta es una buena práctica de programación para los programadores de Delphi, aunque no tengo ninguna prueba. Pre-D2009, no tenemos una forma atómica para devolver un valor, tenemos
exit;
yresult := foo;
ni tan sólo pudiéramos lanzar excepciones.Si tuvieras que sustituir
para
es posible que se canse de ver eso en la parte superior de cada una de sus funciones y prefiera
y solo evita por
exit
completo.fuente
if true then Exit(foo);
utilizo a menudo la técnica a inicializar primeroresult
anil
, oFALSE
, respectivamente, después de comprobar todas las condiciones de error y apenasExit;
si se ha cumplido. El caso de éxitoresult
se establece (típicamente) en algún lugar al final del método.Estoy de acuerdo con la siguiente declaración:
Tomado de esta pregunta en stackoverflow .
fuente
Utilizo retornos tempranos casi exclusivamente en estos días, hasta el extremo. Yo escribo esto
como
pero realmente no importa Si tiene más de uno o dos niveles de anidamiento en sus funciones, deben ser eliminados.
fuente
Prefiero escribir:
fuente
DoSomeFunctionIfSomeCondition
?Como tú, generalmente escribo el primero, pero prefiero el último. Si tengo muchas comprobaciones anidadas, generalmente refactorizo al segundo método.
No me gusta cómo el manejo de errores se aleja del cheque.
Prefiero esto:
fuente
Las condiciones en la parte superior se denominan "condiciones previas". Al poner
if(!precond) return;
, está visualmente enumerando todas las condiciones previas.El uso del bloque "if-else" grande puede aumentar la sobrecarga de sangría (olvidé la cita sobre sangrías de 3 niveles).
fuente
Prefiero mantener si las declaraciones son pequeñas.
Entonces, elegir entre:
y
Elegiría lo que describiste como "regreso temprano".
Eso sí, no me importan los retornos tempranos o lo que sea, simplemente me gusta simplificar el código, acortar los cuerpos de las declaraciones if, etc.
Los anidados si y para y mientras son horribles , evítalos a toda costa.
fuente
Como otros dicen, depende. Para pequeñas funciones que devuelven valores, puedo codificar devoluciones tempranas. Pero para funciones importantes, me gusta tener siempre un lugar en el código donde sé que puedo poner algo que se ejecutará antes de que regrese.
fuente
Practico a prueba de fallas en el nivel de función. Mantiene el código consistente y limpio (para mí y aquellos con los que he trabajado). Por eso siempre regreso temprano.
Para algunas condiciones verificadas con frecuencia, puede implementar aspectos para esas verificaciones si usa AOP.
fuente