Acho que o @JackAidley já disse o essencial , mas deixe-me formulá-lo assim:
sem exceções (por exemplo, C)
No fluxo de código regular, você tem:
if (condition) {
statement;
} else if (less_likely_condition) {
less_likely_statement;
} else {
least_likely_statement;
}
more_statements;
No caso de "erro de saída antecipada", seu código diz:
/* demonstration example, do NOT code like this */
if (condition) {
statement;
} else {
error_handling;
return;
}
Se você detectar esse padrão - a return
em um else
(ou mesmo if
) bloco, refaça-o imediatamente para que o código em questão não tenha um else
bloco:
/* 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 seja profundo demais e atenda ao caso “sair cedo” (ajuda a manter a mente - e o fluxo do código - limpos) e não viola o “colocar a coisa mais provável na if
parte”, porque simplesmente não há else
parte .
C
e limpeza
Inspirado por uma resposta em uma pergunta semelhante (que entendeu errado), veja 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 recolhê-los em um 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);
}
Esse uso de goto
é perfeitamente bom, se você puder lidar com isso; o conselho para não usar goto
é dirigido a pessoas que ainda não podem decidir por si mesmas 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, o que eu prefiro muito (posso usar o tratamento explícito de erros muito melhor e com muito menos surpresa). 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 ;)
Mas aqui está uma sugestão de como você o faz bem em um idioma com exceções e quando você deseja usá-los bem:
retorno de erro em face de exceções
Você pode substituir a maioria dos primeiros return
s com lançando uma exceção. No entanto , o fluxo normal do programa, ou seja, qualquer fluxo de código no qual o programa não tenha encontrado, bem, uma exceção ... uma condição de erro ou algo assim, não deve gerar 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 com que o Operations pareça estranho para você (“esses programadores Java ™ sempre nos dizem que essas exceções são normais”) e pode dificultar a depuração (por exemplo, diga ao IDE para interromper qualquer exceção). As exceções geralmente exigem que o ambiente de tempo de execução desenrole a pilha para produzir rastreios, etc. Há provavelmente mais razões contra isso.
Isso se resume a: em um idioma que suporta exceções, use o que corresponder à lógica e estilo existentes e parecer natural. Se escrever algo do zero, faça isso com antecedência. Se estiver escrevendo uma biblioteca do zero, pense nos seus consumidores. (Também nunca use abort()
em uma biblioteca ...) Mas, faça o que fizer, como regra geral, não haverá uma exceção se a operação continuar (mais ou menos) normalmente após ela.
conselho geral wrt. Exceções
Tente obter todo o uso de exceções no programa acordado por toda a equipe de desenvolvedores primeiro. 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 o pensamento.