Essa noção de entrada única, saída única (SESE) vem de idiomas com gerenciamento explícito de recursos , como C e assembly. Em C, códigos como este vazarão recursos:
void f()
{
resource res = acquire_resource(); // think malloc()
if( f1(res) )
return; // leaks res
f2(res);
release_resource(res); // think free()
}
Nesses idiomas, você basicamente tem três opções:
Replicar o código de limpeza.
Ugh. Redundância é sempre ruim.
Use a goto
para pular para o código de limpeza.
Isso requer que o código de limpeza seja a última coisa na função. (E é por isso que alguns argumentam que goto
tem seu lugar. E de fato - em C.)
Introduzir uma variável local e manipular o fluxo de controle através disso.
A desvantagem é que o fluxo de controle manipulados através de sintaxe (pense break
, return
, if
, while
) é muito mais fácil de seguir do que o fluxo de controle manipulado através do estado de variáveis (porque essas variáveis não têm estado quando você olha para o algoritmo).
Na montagem, é ainda mais estranho, porque você pode pular para qualquer endereço de uma função ao chamá-la, o que efetivamente significa que você tem um número quase ilimitado de pontos de entrada para qualquer função. (Às vezes, isso é útil. Esses thunks são uma técnica comum para os compiladores implementarem o this
ajuste do ponteiro necessário para chamar virtual
funções em cenários de herança múltipla em C ++.)
Quando você precisa gerenciar recursos manualmente, explorar as opções de entrada ou saída de uma função em qualquer lugar leva a um código mais complexo e, portanto, a erros. Portanto, surgiu uma escola de pensamento que propagou o SESE, a fim de obter um código mais limpo e menos erros.
No entanto, quando um idioma apresenta exceções, (quase) qualquer função pode ser encerrada prematuramente (quase) a qualquer momento, portanto, você precisa prever o retorno prematuro de qualquer maneira. (Eu acho que finally
é usado principalmente para isso em Java e using
(ao implementar IDisposable
, finally
caso contrário) em C #; o C ++ emprega RAII .) Depois de fazer isso, você não pode deixar de se limpar devido a uma return
declaração anterior, então o que provavelmente é o argumento mais forte a favor do SESE desapareceu.
Isso deixa legibilidade. Obviamente, uma função 200 LoC com meia dúzia de return
instruções espalhadas aleatoriamente sobre ele não é um bom estilo de programação e não cria código legível. Mas essa função também não seria fácil de entender sem esses retornos prematuros.
Nos idiomas em que os recursos não são ou não devem ser gerenciados manualmente, há pouco ou nenhum valor em aderir à antiga convenção SESE. OTOH, como argumentei acima, o SESE geralmente torna o código mais complexo . É um dinossauro que (exceto C) não se encaixa bem na maioria das línguas atuais. Em vez de ajudar a compreensibilidade do código, ele dificulta.
Por que os programadores Java mantêm isso? Eu não sei, mas do meu POV (externo), o Java pegou muitas convenções de C (onde elas fazem sentido) e as aplicou ao seu mundo OO (onde são inúteis ou totalmente ruins), onde agora se apega a eles, não importa quais sejam os custos. (Como a convenção para definir todas as suas variáveis no início do escopo.)
Os programadores aderem a todos os tipos de notações estranhas por razões irracionais. (Declarações estruturais profundamente aninhadas - "pontas de flechas" - eram, em idiomas como Pascal, uma vez vistas como um belo código.) A aplicação de raciocínio lógico puro a isso parece falhar em convencer a maioria deles a se desviar de seus modos estabelecidos. A melhor maneira de mudar esses hábitos é provavelmente ensinando-os desde cedo a fazer o que é melhor, não o que é convencional. Você, sendo professor de programação, tem na sua mão.:)