Creo que @JackAidley dijo lo esencial de esto , pero permítame formularlo así:
sin excepciones (por ejemplo, C)
En el flujo de código normal, tienes:
if (condition) {
statement;
} else if (less_likely_condition) {
less_likely_statement;
} else {
least_likely_statement;
}
more_statements;
En el caso de "error out early", su código se lee de repente:
/* 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
), vuelva a trabajar de inmediato para que el código en cuestión no tenga un bloque else
:
/* 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 con el caso de "romperse temprano" (ayuda a mantener la mente, y el flujo de código, limpio) y no viola el "poner lo más probable en la parte if
" porque simplemente no hay parte else
.
C
y limpieza
Inspirado por una respuesta a una pregunta similar (que se equivocó), así es como se hace la limpieza con C. Puedes 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 puedes manejarlo; El consejo de no usar goto
está dirigido a personas que aún no pueden decidir por sí mismas si un uso es bueno, aceptable, malo, 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 mucho menos sorpresa). Para citar 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 sobre cómo hacerlo bien en un idioma con excepciones, y cuándo quiere usarlas bien:
devolución de errores ante las excepciones
Puedes reemplazar la mayoría de los primeros return
s con lanzar una excepción. Sin embargo, , su flujo de programa normal , es decir, cualquier flujo de código en el que el programa no haya encontrado, bueno, una excepción ... una condición de error o algo así, no deberá plantea cualquier 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 lo es. Básicamente, una excepción no es un elemento de flujo de control . Esto también hace que las Operaciones se vean raras para usted ("esos programadores de Java ™ siempre nos dicen que estas excepciones son normales") y pueden dificultar la depuración (por ejemplo, decirle al IDE que solo debe interrumpir cualquier excepción). Las excepciones a menudo requieren que el entorno de tiempo de ejecución desenrolle la pila para producir rastreos, etc. Probablemente haya más razones para ello.
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 escribes algo desde cero, haz que esto se acuerde pronto. Si escribe una biblioteca desde cero, piense en sus consumidores. (No, nunca, use abort()
en una biblioteca tampoco ...) Pero haga lo que haga, como regla general, no se lance una excepción si la operación continúa (más o menos) normalmente después de ella.
consejo general wrt. Excepciones
Intente obtener todo el uso de Excepciones acordado en el programa primero por todo el equipo de desarrollo. Básicamente, planificarlos. 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 el pensamiento.