Creo que @JackAidley ya dijo lo esencial , pero déjame formularlo así:
sin excepciones (por ejemplo, C)
En el flujo de código regular, tiene:
if (condition) {
statement;
} else if (less_likely_condition) {
less_likely_statement;
} else {
least_likely_statement;
}
more_statements;
En el caso de "error fuera temprano", su código de repente dice:
/* demonstration example, do NOT code like this */
if (condition) {
statement;
} else {
error_handling;
return;
}
Si ve este patrón, un return
en un bloque else
(o incluso if
), modifíquelo de inmediato para que el código en cuestión no tenga un else
bloque:
/* only code like this at University, to please structured programming professors */
function foo {
if (condition) {
lots_of_statements;
}
return;
}
En el mundo real…
/* code like this instead */
if (!condition) {
error_handling;
return;
}
lots_of_statements;
Esto evita el anidamiento demasiado profundo y cumple el caso de "salir temprano" (ayuda a mantener limpia la mente y el flujo del código) y no viola el "poner lo más probable en la if
parte" porque simplemente no hay else
parte .
C
y limpieza
Inspirado por una respuesta a una pregunta similar (que se equivocó), así es como se realiza la limpieza con C. Puede usar uno o dos puntos de salida allí, aquí hay uno para dos puntos de salida:
struct foo *
alloc_and_init(size_t arg1, int arg2)
{
struct foo *res;
if (!(res = calloc(sizeof(struct foo), 1)))
return (NULL);
if (foo_init1(res, arg1))
goto err;
res.arg1_inited = true;
if (foo_init2(&(res->blah), arg2))
goto err;
foo_init_complete(res);
return (res);
err:
/* safe because we use calloc and false == 0 */
if (res.arg1_inited)
foo_dispose1(res);
free(res);
return (NULL);
}
Puede contraerlos en un punto de salida si hay menos limpieza que hacer:
char *
NULL_safe_strdup(const char *arg)
{
char *res = NULL;
if (arg == NULL)
goto out;
/* imagine more lines here */
res = strdup(arg);
out:
return (res);
}
Este uso de goto
está perfectamente bien, si puede manejarlo; El consejo para evitar el uso goto
está dirigido a personas que aún no pueden decidir por sí mismas si un uso es bueno, aceptable, malo, con código de espagueti u otra cosa.
Excepciones
Lo anterior habla de idiomas sin excepciones, que yo prefiero (puedo usar el manejo explícito de errores mucho mejor y con mucha menos sorpresa). Para citar a igli:
<igli> exceptions: a truly awful implementation of quite a nice idea.
<igli> just about the worst way you could do something like that, afaic.
<igli> it's like anti-design.
<mirabilos> that too… may I quote you on that?
<igli> sure, tho i doubt anyone will listen ;)
Pero aquí hay una sugerencia de cómo hacerlo bien en un idioma con excepciones, y cuándo quiere usarlos bien:
error de retorno ante excepciones
Puede reemplazar la mayoría de los primeros return
s con una excepción. Sin embargo , el flujo normal de su programa, es decir, cualquier flujo de código en el que el programa no encontró, bueno, una excepción ... una condición de error o algo así, no generará ninguna excepción.
Esto significa que…
# this page is only available to logged-in users
if not isLoggedIn():
# this is Python 2.5 style; insert your favourite raise/throw here
raise "eh?"
... está bien, pero ...
/* do not code like this! */
try {
openFile(xyz, "rw");
} catch (LockedException e) {
return "file is locked";
}
closeFile(xyz);
return "file is not locked";
… no es. Básicamente, una excepción no es un elemento de flujo de control . Esto también hace que las operaciones te parezcan extrañas ("esos programadores de Java ™ siempre nos dicen que estas excepciones son normales") y pueden dificultar la depuración (por ejemplo, decirle al IDE que simplemente se salte cualquier excepción). Las excepciones a menudo requieren que el entorno de tiempo de ejecución desenrolle la pila para producir trazas, etc. Probablemente haya más razones en su contra.
Esto se reduce a: en un lenguaje que admite excepciones, use lo que coincida con la lógica y el estilo existentes y se sienta natural. Si escribe algo desde cero, acuerde esto pronto. Si escribe una biblioteca desde cero, piense en sus consumidores. (No, nunca, use abort()
en una biblioteca tampoco ...) Pero haga lo que haga, por regla general, no haga que se lance una excepción si la operación continúa (más o menos) normalmente después de eso.
consejos generales wrt. Excepciones
Trate de obtener todo el uso del programa de Excepciones acordadas por todo el equipo de desarrollo primero. Básicamente, planifícalos. No los uses en abundancia. A veces, incluso en C ++, Java ™, Python, un retorno de error es mejor. A veces no lo es; úsalos con pensamiento.