¿Pasar funciones a otras funciones como parámetros, mala práctica?

39

Hemos estado en el proceso de cambiar la forma en que nuestra aplicación AS3 habla con nuestro back-end y estamos en el proceso de implementar un sistema REST para reemplazar el anterior.

Lamentablemente, el desarrollador que comenzó el trabajo ahora está en baja por enfermedad a largo plazo y me lo han entregado. He estado trabajando con él durante la última semana más o menos y entiendo el sistema, pero hay una cosa que me preocupa. Parece que hay muchas funciones que pasan a funciones. Por ejemplo, nuestra clase que realiza la llamada a nuestros servidores toma una función a la que luego llamará y pasará un objeto cuando el proceso se complete y se hayan manejado los errores, etc.

Me está dando ese "mal presentimiento" en el que siento que es una práctica horrible y puedo pensar en algunas razones por las que, pero quiero una confirmación antes de proponer un nuevo trabajo al sistema. Me preguntaba si alguien tenía alguna experiencia con este posible problema.

    
pregunta Elliot Blackburn 20.08.2014 - 11:39

5 respuestas

83

No es un problema.

Es una técnica conocida. Estas son funciones de orden superior (funciones que toman funciones como parámetros).

Este tipo de función es también un componente básico en programación funcional y se usa ampliamente en lenguajes funcionales como < a href="http://www.haskell.org/haskellwiki/Haskell"> Haskell .

Dichas funciones no son malas ni buenas: si nunca ha encontrado la noción y la técnica, al principio puede ser difícil de comprender, pero pueden ser muy poderosas y son una buena herramienta para su cinturón de herramientas.

    
respondido por el Oded 20.08.2014 - 11:48
30

No solo se utilizan para la programación funcional. También pueden conocerse como devoluciones de llamada :

  

Una devolución de llamada es un fragmento de código ejecutable que se pasa como un argumento a otro código, que se espera que devuelva (ejecute) el argumento en algún momento conveniente. La invocación puede ser inmediata como en una devolución de llamada sincrónica o puede ocurrir en un momento posterior, como en una devolución de llamada asíncrona.

Piense en el código asíncrono por un segundo. Se pasa a una función que, por ejemplo, envía datos al usuario. Solo cuando el código se ha completado, invoca esta función con el resultado de la respuesta, que luego utiliza la función para enviar los datos al usuario. Es un cambio de mentalidad.

Escribí una biblioteca que recupera datos de Torrent de tu seedbox. Está utilizando un bucle de eventos no bloqueantes para ejecutar esta biblioteca y obtener datos, y luego devolverlos al usuario (por ejemplo, en un contexto de websocket). Imagina que tienes 5 personas conectadas en este bucle de eventos y una de las solicitudes para obtener los puestos de datos de torrent de alguien. Eso bloqueará todo el bucle. Por lo tanto, debe pensar de forma asíncrona y utilizar devoluciones de llamada: el bucle se sigue ejecutando y el proceso de "devolver los datos al usuario" solo se ejecuta cuando la función ha finalizado su ejecución, por lo que no hay que esperar. Dispara y olvida.

    
respondido por el James 20.08.2014 - 17:45
11

Esto no es algo malo. De hecho, es algo muy bueno.

Pasar funciones a funciones es tan importante para la programación que inventamos funciones lambda como una taquigrafía. Por ejemplo, uno puede usar lambdas con algoritmos de C ++ para escribir muy compacta sin embargo, un código expresivo que permite a un algoritmo genérico la capacidad de usar variables locales y otros estados para hacer cosas como buscar y clasificar.

Las bibliotecas orientadas a objetos también pueden tener devoluciones de llamada que son esencialmente interfaces que especifican un pequeño número de funciones ( idealmente uno, pero no siempre). Entonces se puede crear una clase simple que implemente esa interfaz y pasar un objeto de esa clase a una función. Esa es una piedra angular de la programación dirigida por eventos , donde el código a nivel de marco (quizás incluso en otro hilo) necesita llamar a un objeto para cambiar el estado en respuesta a una acción del usuario. El ActionListener de Java es un buen ejemplo de esto.

Técnicamente, un functor de C ++ también es un tipo de objeto de devolución de llamada que aprovecha el azúcar sintáctico, operator()() , para hacer lo mismo.

Finalmente, hay punteros de función de estilo C que solo deberían usarse en C. No voy a entrar en detalles, solo los menciono para completarlos. Las otras abstracciones mencionadas anteriormente son muy superiores y deben usarse en los idiomas que las tienen.

Otros han mencionado la programación funcional y cómo las funciones de paso son muy naturales en esos lenguajes. Lambdas y las devoluciones de llamada son la forma en que los lenguajes de procedimiento y OOP imitan eso, y son muy potentes y útiles.

    
respondido por el user22815 21.08.2014 - 06:51
6

Como ya se dijo, no es una mala práctica. Es simplemente una forma de disociar y separar la responsabilidad. Por ejemplo, en OOP harías algo como esto:

public void doSomethingGeneric(ISpecifier specifier) {
    //do generic stuff
    specifier.doSomethingSpecific();
    //do some other generic stuff
}

El método genérico es delegar una tarea específica, de la que no sabe nada, a otro objeto que implementa una interfaz. El método genérico solo conoce esta interfaz. En su caso, esta interfaz sería una función a la que se debe llamar.

    
respondido por el Philipp Murry 20.08.2014 - 11:55
3

En general, no hay nada de malo en pasar las funciones a otras funciones. Si está realizando llamadas asíncronas y quiere hacer algo con el resultado, entonces necesitará algún tipo de mecanismo de devolución de llamada.

Sin embargo, hay algunos inconvenientes potenciales de las devoluciones de llamada simples:

  • Hacer una serie de llamadas puede requerir un anidamiento profundo de las devoluciones de llamada.
  • El manejo de errores puede necesitar repetición para cada llamada en una secuencia de llamadas.
  • Coordinar múltiples llamadas es incómodo, como hacer múltiples llamadas al mismo tiempo y luego hacer algo una vez que están todos terminados.
  • No hay una forma general de cancelar un conjunto de llamadas.

Con los servicios web simples, la forma en que lo haces funciona bien, pero se vuelve incómodo si necesitas una secuencia de llamadas más compleja. Sin embargo, hay algunas alternativas. Con JavaScript, por ejemplo, ha habido un cambio hacia el uso de promesas ( Lo que es tan bueno acerca de las promesas de javascript ).

Todavía implican pasar funciones a otras funciones, pero las llamadas asíncronas devuelven un valor que toma una devolución de llamada en lugar de una devolución de llamada directamente a sí mismas. Esto da más flexibilidad para componer estas llamadas juntas. Algo como esto se puede implementar con bastante facilidad en ActionScript.

    
respondido por el fgb 20.08.2014 - 22:04

Lea otras preguntas en las etiquetas