coding-style - studio - superponer graficas en r
¿Por qué debería una función tener solo un punto de salida? (8)
Siempre escuché acerca de una función de punto de salida como una mala forma de codificar porque pierde legibilidad y eficiencia. Nunca escuché a nadie discutir el otro lado.
Pensé que esto tenía algo que ver con CS, pero esta pregunta fue derribada en cstheory stackexchange.
Con casi todo, se reduce a las necesidades del entregable. En "los viejos tiempos", el código de spaghetti con múltiples puntos de retorno invitaba a pérdidas de memoria, ya que los codificadores que preferían ese método generalmente no se limpiaban bien. También hubo problemas con algunos compiladores que "perdieron" la referencia a la variable de retorno a medida que la pila aparecía durante el retorno, en el caso de regresar de un alcance anidado. El problema más general fue el del código de reentrada, que intenta que el estado de llamada de una función sea exactamente el mismo que el de retorno. Mutadores de oop violaron esto y el concepto fue archivado.
Hay entregables, especialmente kernels, que necesitan la velocidad que proporcionan los puntos de salida múltiples. Estos entornos normalmente tienen su propia memoria y administración de procesos, por lo que se minimiza el riesgo de una fuga.
Personalmente, me gusta tener un único punto de salida, ya que a menudo lo uso para insertar un punto de interrupción en la declaración de devolución y realizar una inspección del código de cómo el código determinó esa solución. Podría simplemente ir a la entrada y dar un paso adelante, lo cual hago con soluciones extensivamente anidadas y recursivas. Como revisor de código, los retornos múltiples en una función requieren un análisis mucho más profundo, por lo que si lo hace para acelerar la implementación, le está robando a Peter para salvar a Paul. Se necesitará más tiempo para revisar los códigos, lo que invalida la presunción de una implementación eficiente.
- 2 centavos
Consulte este documento para obtener más información: NISTIR 5459
El punto de entrada y salida único fue el concepto original de programación estructurada, paso a paso, codificación espagueti. Existe la creencia de que las funciones de puntos de salida múltiples requieren más código ya que debe hacer una limpieza adecuada de los espacios de memoria asignados para las variables. Considere un escenario en el que la función asigna variables (recursos) y salir de la función antes de tiempo y sin una limpieza adecuada se producirían fugas de recursos. Además, construir una limpieza antes de cada salida crearía una gran cantidad de código redundante.
En mi opinión, el consejo de salir de una función (u otra estructura de control) en un solo punto a menudo está sobrevendido. Por lo general, se dan dos razones para salir solo en un punto:
- El código de salida única es supuestamente más fácil de leer y depurar. (Admito que no creo mucho de esta razón, pero se da. Lo que es sustancialmente más fácil de leer y depurar es el código de entrada única).
- Enlaces de código de salida única y devuelve más limpio.
La segunda razón es sutil y tiene algún mérito, especialmente si la función devuelve una gran estructura de datos. Sin embargo, no me preocuparía demasiado, excepto ...
Si eres un estudiante, quieres obtener las mejores notas en tu clase. Haz lo que el instructor prefiera. Probablemente tiene una buena razón desde su perspectiva; así que, al menos, aprenderás su perspectiva. Esto tiene valor en sí mismo.
Buena suerte.
Existen diferentes escuelas de pensamiento, y en gran parte se reduce a las preferencias personales.
Una es que es menos confuso si solo hay un punto de salida único: tiene una ruta única a través del método y usted sabe dónde buscar la salida. En el lado negativo, si usa la sangría para representar el anidamiento, su código termina sangrando masivamente hacia la derecha, y se vuelve muy difícil seguir todos los ámbitos anidados.
Otra es que puede verificar condiciones previas y salir temprano al inicio de un método, para que sepa en el cuerpo del método que ciertas condiciones son verdaderas, sin que todo el cuerpo del método se sancione a 5 millas hacia la derecha. Esto generalmente minimiza la cantidad de ámbitos de los que debe preocuparse, lo que hace que el código sea mucho más fácil de seguir.
Un tercero es que puedes salir donde quieras. Esto solía ser más confuso en los viejos tiempos, pero ahora que tenemos editores y compiladores coloreadores de sintaxis que detectan códigos inalcanzables, es mucho más fácil lidiar con ellos.
Estoy en el medio campo. Aplicar un solo punto de salida es una restricción inútil o incluso contraproducente en mi humilde opinión, mientras que salir al azar por un método a veces puede llevar a una lógica difícil de seguir, donde es difícil ver si un determinado bit de código será o no será ejecutado. Pero "activar" tu método hace que sea posible simplificar significativamente el cuerpo del método.
La respuesta depende mucho del contexto. Si está haciendo una GUI y tiene una función que inicializa API y abre ventanas al inicio de su main, estará llena de llamadas que pueden arrojar errores, cada uno de los cuales provocaría que la instancia del programa se cierre. Si utilizó declaraciones IF anidadas y sangría, su código podría volverse rápidamente muy sesgado a la derecha. Volver a un error en cada etapa puede ser mejor y, en realidad, más legible, mientras que es tan fácil de depurar con unos pocos indicadores en el código.
Sin embargo, si está probando diferentes condiciones y devolviendo valores diferentes según los resultados de su método, es mejor que tenga un solo punto de salida. Solía trabajar en scripts de procesamiento de imágenes en MATLAB, que podían ser muy grandes. Múltiples puntos de salida podrían hacer que el código sea extremadamente difícil de seguir. Las declaraciones de cambio fueron mucho más apropiadas.
Lo mejor que puedes hacer es aprender sobre la marcha. Si está escribiendo código para algo, intente encontrar el código de otras personas y vea cómo lo implementan. Decide qué bits te gustan y qué bits no.
Mi recomendación general es que las declaraciones de retorno deben, cuando sea práctico, ubicarse antes del primer código que tenga algún efecto secundario o después del último código que tenga algún efecto secundario. Consideraría algo como:
if (!argument) // Check if non-null return ERR_NULL_ARGUMENT; ... process non-null argument if (ok) return 0; else return ERR_NOT_OK;
más claro que:
int return_value; if (argument) // Non-null { .. process non-null argument .. set result appropriately } else result = ERR_NULL_ARGUMENT; return result;
Si una determinada condición impide que una función haga algo, prefiero regresar temprano de la función en un punto por encima del punto donde la función haría cualquier cosa. Sin embargo, una vez que la función ha emprendido acciones con efectos secundarios, prefiero volver desde abajo para dejar en claro que se deben tratar todos los efectos secundarios.
Si siente que necesita múltiples puntos de salida en una función, la función es demasiado grande y está haciendo demasiado.
Yo recomendaría leer el capítulo sobre funciones en el libro de Robert C. Martin, Código limpio.
Esencialmente, debe intentar escribir funciones con 4 líneas de código o menos.
Algunas notas del blog de Mike Long :
- La primera regla de funciones: deben ser pequeñas
- La segunda regla de funciones: deben ser más pequeñas que eso
- Los bloques dentro de sentencias if, mientras que los enunciados, para bucles, etc. deben ser de una línea de longitud
- ... y esa línea de código generalmente será una llamada a función
- No debe haber más de uno o tal vez dos niveles de sangría
- Las funciones deberían hacer una cosa
- Las declaraciones de la función deberían estar en el mismo nivel de abstracción
- Una función no debe tener más de 3 argumentos
- Los argumentos de salida son un olor a código
- Pasar una bandera booleana a una función es realmente horrible. Por definición estás haciendo dos cosas en la función.
- Los efectos secundarios son mentiras.
Solía ser un defensor del estilo de salida única. Mi razonamiento proviene principalmente del dolor ...
Single-exit es más fácil de depurar.
Teniendo en cuenta las técnicas y herramientas que tenemos hoy en día, esta es una posición mucho menos razonable que tomar como pruebas unitarias y el registro puede hacer innecesaria la salida única. Dicho esto, cuando necesitas ver el código ejecutarse en un depurador, es mucho más difícil de entender y trabajar con código que contiene múltiples puntos de salida.
Esto se hizo especialmente cierto cuando necesitó interponer asignaciones para examinar el estado (reemplazado con expresiones de reloj en depuradores modernos). También era demasiado fácil alterar el flujo de control de forma que ocultaba el problema o rompía la ejecución por completo.
Los métodos de salida única fueron más fáciles de recorrer en el depurador y más fáciles de separar sin romper la lógica.