Eu acho que o @JackAidley disse a essência dele , mas deixe-me formular assim:
sem exceções (por exemplo, C)
No fluxo de código normal, você tem:
if (condition) {
statement;
} else if (less_likely_condition) {
less_likely_statement;
} else {
least_likely_statement;
}
more_statements;
No caso "error out early", seu código lê de repente:
/* demonstration example, do NOT code like this */
if (condition) {
statement;
} else {
error_handling;
return;
}
Se você identificar esse padrão, um return
em um bloco else
(ou mesmo if
), refazer o código imediatamente para que o código em questão não tenha um bloco else
:
/* only code like this at University, to please structured programming professors */
function foo {
if (condition) {
lots_of_statements;
}
return;
}
No mundo real ...
/* code like this instead */
if (!condition) {
error_handling;
return;
}
lots_of_statements;
Isso evita que o aninhamento muito profundo e atenda ao caso "break out early" (ajuda a manter a mente - e o fluxo de código - limpo) e não viola o "coloque a coisa mais provável na parte if
" porque simplesmente não há else
part.
C
e limpeza
Inspirado por uma resposta em uma pergunta semelhante (que deu errado), aqui está como você faz a limpeza com C. Você pode usar um ou dois pontos de saída, aqui está um para dois pontos de saída:
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);
}
Você pode colapsá-los em um único ponto de saída se houver menos limpeza a fazer:
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á perfeitamente bem, se você puder lidar com isso; o conselho para ficar de fora usando goto
é direcionado a pessoas que ainda não podem decidir sozinhas se um uso é bom, aceitável, ruim, código de espaguete ou qualquer outra coisa.
Exceções
O texto acima fala sobre idiomas sem exceções, que eu prefiro muito a mim mesmo (eu posso usar o erro explícito para lidar com muito melhor e com muito menos surpresa). Para citar o 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 ;)
Mas aqui está uma sugestão de como você faz isso em um idioma com exceções e quando deseja usá-las bem:
Retorno de erro
em face de exceções
Você pode substituir a maior parte dos primeiros return
s com uma exceção. No entanto , seu fluxo de programa normal , ou seja, qualquer fluxo de código no qual o programa não encontrou, bem, uma exceção… uma condição de erro ou algo assim, não levantar quaisquer exceções.
Isso 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á bem, mas…
/* do not code like this! */
try {
openFile(xyz, "rw");
} catch (LockedException e) {
return "file is locked";
}
closeFile(xyz);
return "file is not locked";
… não é. Basicamente, uma exceção não é um elemento de fluxo de controle . Isso também faz as Operações parecerem estranhas para você (“os programadores Java ™ sempre nos dizem que essas exceções são normais”) e podem impedir a depuração (por exemplo, dizer ao IDE para quebrar apenas qualquer exceção). As exceções geralmente exigem que o ambiente de tempo de execução libere a pilha para produzir tracebacks, etc. Provavelmente há mais motivos para isso.
Isso se resume a: em uma linguagem que aceita exceções, use o que corresponder à lógica e ao estilo existentes e pareça natural. Se estiver escrevendo algo do zero, aceite isso com antecedência. Se estiver escrevendo uma biblioteca do zero, pense nos seus consumidores. (Nunca use abort()
em uma biblioteca ...) Mas, faça o que fizer, como regra geral, uma exceção será lançada se a operação continuar (mais ou menos) normalmente depois dela.
conselho geral. Exceções
Tente obter todas as exceções acordadas por toda a equipe de desenvolvedores primeiro no programa. Basicamente, planeje-os. Não os use em abundância. Às vezes, mesmo em C ++, Java ™, Python, um retorno de erro é melhor. Às vezes não é; use-os com pensamento.