Esta noción de Entrada única, Salida única (SESE) proviene de idiomas con gestión explícita de recursos , como C y ensamblaje. En C, código como este perderá recursos:
void f()
{
resource res = acquire_resource(); // think malloc()
if( f1(res) )
return; // leaks res
f2(res);
release_resource(res); // think free()
}
En dichos idiomas, básicamente tienes tres opciones:
-
Replica el código de limpieza.
Ugh La redundancia siempre es mala.
-
Use un goto
para saltar al código de limpieza.
Esto requiere que el código de limpieza sea lo último en la función. (Y esta es la razón por la que algunos argumentan que goto
tiene su lugar. Y de hecho tiene - en C)
-
Introduzca una variable local y manipule el flujo de control a través de eso.
La desventaja es que el flujo de control manipulado a través de la sintaxis (piense en break
, return
, if
, while
) es mucho más fácil de seguir que el flujo de control manipulado a través del estado de las variables (porque esas variables no tienen estado cuando mira el algoritmo).
En ensamblaje es aún más extraño, porque puedes saltar a cualquier dirección en una función cuando llamas a esa función, lo que efectivamente significa que tienes un número casi ilimitado de puntos de entrada a cualquier función. (A veces, esto es útil. Tales trucos son una técnica común para que los compiladores implementen el ajuste de puntero this
necesario para llamar a las funciones virtual
en escenarios de herencia múltiple en C ++).
Cuando tiene que administrar recursos manualmente, explotar las opciones de ingresar o salir de una función en cualquier lugar conduce a un código más complejo y, por lo tanto, a errores. Por lo tanto, apareció una escuela de pensamiento que propagó SESE, para obtener un código más limpio y menos errores.
Sin embargo, cuando un idioma presenta excepciones, (casi) cualquier función puede salir prematuramente en (casi) cualquier punto, por lo que debe hacer provisiones para un retorno prematuro de todos modos. (Creo que finally
se usa principalmente para eso en Java y using
(cuando se implementa IDisposable
, finally
de lo contrario) en C #; C ++ en cambio emplea RAII .) Una vez que haya hecho esto, no puede limpiar después de usted debido a una declaración return
temprana, entonces, ¿cuál es probablemente el argumento más sólido en El favor de SESE ha desaparecido.
Eso deja legibilidad. Por supuesto, una función de 200 LoC con media docena de declaraciones de return
esparcidas aleatoriamente no es un buen estilo de programación y no constituye un código legible. Pero tal función tampoco sería fácil de entender sin esos rendimientos prematuros.
En los idiomas donde los recursos no son o no deben administrarse manualmente, hay poco o ningún valor en adherirse a la antigua convención SESE. OTOH, como he argumentado anteriormente, SESE a menudo hace que el código sea más complejo . Es un dinosaurio que (a excepción de C) no encaja bien en la mayoría de los idiomas de hoy. En lugar de ayudar a la comprensión del código, lo dificulta.
¿Por qué los programadores de Java se apegan a esto? No lo sé, pero desde mi punto de vista (externo), Java tomó muchas convenciones de C (donde tienen sentido) y las aplicó a su mundo OO (donde son inútiles o totalmente malas), donde ahora se adhiere a ellos, no importa lo que cueste. (Al igual que la convención para definir todas sus variables al principio del alcance).
Los programadores se adhieren a todo tipo de notaciones extrañas por razones irracionales. (Declaraciones estructurales profundamente anidadas, "puntas de flecha", se consideraron, en lenguajes como Pascal, un código hermoso). La aplicación de un razonamiento lógico puro a esto parece no convencer a la mayoría de ellos para que se desvíen de sus formas establecidas. La mejor manera de cambiar tales hábitos es, probablemente, enseñarles desde el principio a hacer lo mejor, no lo convencional. Tú, siendo profesor de programación, lo tienes en tu mano. :)