¿Una función debería tener solo una declaración de retorno?
¿Existen buenas razones por las que es mejor tener una sola declaración de devolución en una función?
¿O está bien regresar de una función tan pronto como sea lógicamente correcto hacerlo, lo que significa que puede haber muchas declaraciones de retorno en la función?
A menudo tengo varias declaraciones al comienzo de un método para regresar en situaciones "fáciles". Por ejemplo, esto:
public void DoStuff(Foo foo)
{
if (foo != null)
{
...
}
}
... se puede hacer más legible (en mi humilde opinión) así:
public void DoStuff(Foo foo)
{
if (foo == null) return;
...
}
Entonces sí, creo que está bien tener múltiples "puntos de salida" de una función/método.
Nadie ha mencionado ni citado Code Complete, así que lo haré.
17.1 regreso
Minimizar el número de devoluciones en cada rutina . Es más difícil entender una rutina si, al leerla en la parte inferior, no eres consciente de la posibilidad de que haya regresado a algún lugar superior.
Utilice una devolución cuando mejore la legibilidad . En determinadas rutinas, una vez que sepa la respuesta, querrá devolverla a la rutina de llamada inmediatamente. Si la rutina está definida de tal manera que no requiere ninguna limpieza, no regresar inmediatamente significa que tendrá que escribir más código.
Yo diría que sería increíblemente imprudente decidir arbitrariamente contra múltiples puntos de salida, ya que he encontrado que la técnica es útil en la práctica una y otra vez ; de hecho, a menudo he refactorizado el código existente a múltiples puntos de salida para mayor claridad. Podemos comparar los dos enfoques así: -
string fooBar(string s, int? i) {
string ret = "";
if(!string.IsNullOrEmpty(s) && i != null) {
var res = someFunction(s, i);
bool passed = true;
foreach(var r in res) {
if(!r.Passed) {
passed = false;
break;
}
}
if(passed) {
// Rest of code...
}
}
return ret;
}
Compare esto con el código donde se permiten múltiples puntos de salida: -
string fooBar(string s, int? i) {
var ret = "";
if(string.IsNullOrEmpty(s) || i == null) return null;
var res = someFunction(s, i);
foreach(var r in res) {
if(!r.Passed) return null;
}
// Rest of code...
return ret;
}
Creo que esto último es considerablemente más claro. Hasta donde puedo decir, la crítica a los múltiples puntos de salida es un punto de vista bastante arcaico en estos días.
Actualmente estoy trabajando en un código base donde dos de las personas que trabajan en él se suscriben ciegamente a la teoría del "punto único de salida" y puedo decirles que, por experiencia, es una práctica horrible. Hace que el código sea extremadamente difícil de mantener y te mostraré por qué.
Con la teoría del "punto único de salida", inevitablemente terminas con un código que se parece a este:
function()
{
HRESULT error = S_OK;
if(SUCCEEDED(Operation1()))
{
if(SUCCEEDED(Operation2()))
{
if(SUCCEEDED(Operation3()))
{
if(SUCCEEDED(Operation4()))
{
}
else
{
error = OPERATION4FAILED;
}
}
else
{
error = OPERATION3FAILED;
}
}
else
{
error = OPERATION2FAILED;
}
}
else
{
error = OPERATION1FAILED;
}
return error;
}
Esto no solo hace que el código sea muy difícil de seguir, sino que ahora digamos que más adelante debes regresar y agregar una operación entre 1 y 2. Tienes que sangrar casi toda la maldita función, y buena suerte asegurándote de que todas sus condiciones if/else y sus llaves coinciden correctamente.
Este método hace que el mantenimiento del código sea extremadamente difícil y propenso a errores.