Pregunta ¿Debería una función tener solo una declaración de retorno?


¿Hay buenas razones por las cuales es una mejor práctica tener solo una declaración de retorno 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?


781


origen


Respuestas:


A menudo tengo varias declaraciones al comienzo de un método para volver a 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) de esta manera:

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.


743



Nadie ha mencionado o citado Código completo así que lo haré.

17.1 vuelta

Minimice el número de devoluciones en cada rutina. Es más difícil entender una rutina si, al leerla en la parte inferior, no estás consciente de la posibilidad de que haya regresado a alguna parte anterior.

Usar una regreso cuando mejora la legibilidad. En ciertas rutinas, una vez que conoce la respuesta, desea devolverla a la rutina de llamadas de inmediato. Si la rutina está definida de tal manera que no requiere ninguna limpieza, no regresar inmediatamente significa que tiene que escribir más código.


355



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 refactorizado código existente a múltiples puntos de salida para mayor claridad. Podemos comparar los dos enfoques de esta manera:

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 múltiples puntos de salida son permitido:-

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 este último es considerablemente más claro. Por lo que puedo decir, la crítica de los puntos de salida múltiples es un punto de vista bastante arcaico en estos días.


229



Actualmente estoy trabajando en una base de código donde dos de las personas que trabajan en ella se suscriben ciegamente a la teoría del "punto de salida único" y puedo decirles que, por experiencia, es una práctica horrible horrible. Hace que el código sea extremadamente difícil de mantener y te mostraré por qué.

Con la teoría del "punto de salida único", inevitablemente terminas con un código que se ve así:

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 dices más tarde que necesitas regresar y agregar una operación entre 1 y 2. Tienes que sangrar casi toda la función maldita, y buena suerte asegurándote de que todos sus condiciones if / else y llaves se emparejan correctamente.

Este método hace que el mantenimiento del código sea extremadamente difícil y propenso a errores.


191



Programación estructurada dice que solo debería tener una declaración de retorno por función. Esto es para limitar la complejidad. Muchas personas como Martin Fowler argumentan que es más simple escribir funciones con declaraciones de devolución múltiples. Presenta este argumento en el clásico refactorización libro que escribió. Esto funciona bien si sigues sus otros consejos y escribes pequeñas funciones. Estoy de acuerdo con este punto de vista y solo los estrictos puristas de la programación estructurada se adhieren a declaraciones de retorno individuales por función.


72



Como Kent Beck señala al discutir las cláusulas de guardia en Patrones de implementación hacer una rutina tiene un solo punto de entrada y salida ...

"fue para evitar la confusión posible   al saltar dentro y fuera de muchos   ubicaciones en la misma rutina. Hecho   buen sentido cuando se aplica a FORTRAN o   programas de lenguaje ensamblador escritos   con una gran cantidad de datos globales donde incluso   entendiendo que declaraciones fueron   ejecutado fue un trabajo duro ... con métodos pequeños y sobre todo datos locales, es innecesariamente conservador ".

Encuentro que una función escrita con cláusulas de guardia es mucho más fácil de seguir que un grupo largo anidado de if then else declaraciones.


62



En una función que no tiene efectos secundarios, no hay una buena razón para tener más de una devolución y debe escribirlos en un estilo funcional. En un método con efectos secundarios, las cosas son más secuenciales (indexadas en el tiempo), por lo que se escribe en un estilo imperativo, usando la declaración return como un comando para detener la ejecución.

En otras palabras, cuando sea posible, favorezca este estilo

return a > 0 ?
  positively(a):
  negatively(a);

Más allá de esto

if (a > 0)
  return positively(a);
else
  return negatively(a);

Si se encuentra escribiendo varias capas de condiciones anidadas, probablemente haya una manera de refactorizar eso, usando la lista de predicados, por ejemplo. Si encuentra que sus ifs y elses están muy separados sintácticamente, puede dividirlos en funciones más pequeñas. Un bloque condicional que abarca más de una pantalla de texto es difícil de leer.

No hay una regla rígida que se aplique a todos los idiomas. Algo como tener una sola declaración de devolución no hará que su código sea bueno. Pero un buen código tenderá a permitirte escribir tus funciones de esa manera.


61



Lo he visto en los estándares de codificación para C ++ que eran un cuelgue de C, como si no tuviera RAII u otra administración automática de memoria, entonces tiene que limpiar para cada devolución, lo que significa cortar y pegar de la limpieza o un goto (lógicamente lo mismo que "finalmente" en los lenguajes administrados), ambos se consideran de mala calidad. Si sus prácticas son usar punteros inteligentes y colecciones en C ++ u otro sistema de memoria automático, entonces no hay una razón fuerte para ello, y se trata de legibilidad, y más de una llamada de juicio.


43



Me inclino a la idea de que las declaraciones de retorno en el medio de la función son malas Puede usar devoluciones para compilar algunas cláusulas de guardia en la parte superior de la función y, por supuesto, decirle al compilador qué devolver al final de la función sin problema, pero regresa en el medio de la función puede ser fácil de perder y puede hacer que la función sea más difícil de interpretar.


40



¿Hay buenas razones por las cuales es una mejor práctica tener solo una declaración de retorno en una función?

, existen:

  • El único punto de salida brinda un excelente lugar para afirmar sus condiciones posteriores.
  • Ser capaz de poner un punto de interrupción del depurador en un retorno al final de la función suele ser útil.
  • Menos retornos significa menos complejidad. El código lineal es generalmente más simple de entender.
  • Si tratar de simplificar una función para obtener un solo retorno causa complejidad, entonces eso es un incentivo para refactorizar a funciones más pequeñas, más generales y fáciles de entender.
  • Si está en un idioma sin destructores o si no usa RAII, una sola devolución reduce la cantidad de lugares que debe limpiar.
  • Algunos idiomas requieren un único punto de salida (por ejemplo, Pascal y Eiffel).

La pregunta a menudo se plantea como una dicotomía falsa entre declaraciones múltiples o declaraciones if profundamente anidadas. Casi siempre hay una tercera solución que es muy lineal (sin anidamiento profundo) con un solo punto de salida.

Actualizar: Aparentemente Las pautas de MISRA promueven una salida única, también.

Para ser claro, no digo que sea siempre mal tener múltiples devoluciones. Pero, dadas las soluciones por lo demás equivalentes, existen muchas buenas razones para preferir el que tiene una sola devolución.


38



Tener un solo punto de salida proporciona una ventaja en la depuración, ya que le permite establecer un único punto de interrupción al final de una función para ver qué valor realmente se va a devolver.


33