Esta noción de entrada única, salida única (SESE) proviene de lenguajes con gestión explícita de recursos , como C y ensamblado. En C, un código como este filtrará recursos:
void f()
{
resource res = acquire_resource(); // think malloc()
if( f1(res) )
return; // leaks res
f2(res);
release_resource(res); // think free()
}
En tales idiomas, básicamente tiene tres opciones:
Replicar el código de limpieza.
Ugh La redundancia siempre es mala.
Use a 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 cual algunos argumentan que goto
tiene su lugar. Y de hecho lo ha hecho, 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 break
, return
, if
, while
) es mucho más fácil de seguir que el flujo de control manipulado por el estado de las variables (ya que estas variables no tienen ningún estado cuando nos fijamos en el algoritmo).
En el ensamblaje es aún más extraño, porque puede saltar a cualquier dirección en una función cuando llama a esa función, lo que significa que tiene un número casi ilimitado de puntos de entrada a cualquier función. (A veces esto es útil. Tales thunks son una técnica común para que los compiladores implementen el this
ajuste de puntero necesario para llamar a virtual
funciones en escenarios de herencia múltiple en C ++).
Cuando tiene que administrar los 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 tomar medidas para el retorno prematuro de todos modos. (Creo que finally
se usa principalmente para eso en Java y using
(cuando se implementa IDisposable
, de lo finally
contrario) en C #; C ++ en su lugar emplea RAII .) Una vez que haya hecho esto, no puede dejar de limpiar después de usted debido a una return
declaración temprana , entonces lo que probablemente sea El argumento más fuerte a favor de SESE ha desaparecido.
Eso deja legibilidad. Por supuesto, una función de 200 LoC con media docena de return
declaraciones esparcidas aleatoriamente sobre ella no es un buen estilo de programación y no genera código legible. Pero tal función tampoco sería fácil de entender sin esos retornos prematuros.
En los idiomas donde los recursos no se administran o no se deben administrar 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 lenguajes actuales. En lugar de ayudar a la comprensión del código, lo dificulta.
¿Por qué los programadores de Java se adhieren 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 directamente malas), donde ahora se adhiere a ellos, sin importar los costos. (Al igual que la convención para definir todas sus variables al comienzo del alcance).
Los programadores se adhieren a todo tipo de notaciones extrañas por razones irracionales. (Las declaraciones estructurales profundamente anidadas - "puntas de flecha" - fueron vistas, en lenguajes como Pascal, una vez como un código hermoso.) Aplicar un razonamiento lógico puro a esto parece no convencer a la mayoría de ellos de desviarse 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. Usted, como profesor de programación, lo tiene en la mano.:)