¿Cuál es el nombre de una función que no toma argumentos y no devuelve nada? [cerrado]

80

En el java.util.functionpaquete de Java 8 , tenemos:

  • Función : toma un argumento, produce un resultado.
  • Consumidor : toma un argumento, no produce nada.
  • Proveedor : no toma argumentos, produce un resultado.
  • ... : Otros casos que manejan primitivas, 2 argumentos, etc.

Pero necesito manejar el caso " no toma argumento, no produce nada ".

No hay nada para esto en java.util.functionnal.

Entonces, la pregunta es:

¿Cuál es el nombre de ' una función que no toma argumentos y no devuelve nada '?

En Java 8, su definición sería:

@FunctionalInterface
public interface InsertANameHere {
    void execute();
}

El ejecutor ya existe y tiene otro propósito: " Un objeto que ejecuta tareas ejecutables enviadas ". La firma no coincide ( execute(Runnable):void) y ni siquiera es una interfaz funcional .

Runnable existe, pero está fuertemente vinculado al contexto de subprocesos:

  • El paquete java.langno lo es java.util.function.
  • El javadoc dice: " La interfaz Runnable debe ser implementada por cualquier clase cuyas instancias estén destinadas a ser ejecutadas por un hilo ".
  • El nombre "Runnable" sugiere un código en ejecución dentro de un hilo.
superbob
fuente
28
"Pero no hay nada para" No toma argumentos, no produce nada "" - ¿ Ejecutable ?
user11153
11
Creo que el javadoc for Runnableestá desactualizado en este momento, porque un Runnable también es utilizado por otras clases que Thread( Executorpor ejemplo).
SpaceTrucker
13
@superbob Eso no significa que Runnables solo pueda ser .run()por Threads. De hecho, se usan muy comúnmente para exactamente el propósito descrito en la pregunta
2015
55
@superbob Ese fue su propósito inicial, pero desde Java 8 se "actualizó" como interfaz funcional. Por eso no encontraste nada en el java.util.function paquete.
user11153
55
Semi-Snark: ImpureFuntion porque seguramente solo depende de los efectos secundarios, de lo contrario es un no-op. ( en.wikipedia.org/wiki/Pure_function#Impure_functions ) Más en serio: Imperativo (hacer algo), que al menos coincidiría con la semántica de void execute ();
Kristian H

Respuestas:

71

La elección de Java de hacerlo de esa manera con un nombre separado para cada arity fue estúpida. No vale exactamente la pena emular. Sin embargo, si debe hacerlo en aras de la coherencia, o si está escribiendo un código de biblioteca muy genérico, las sugerencias de Konrad son buenas. Podría arrojarme Procedureal ring.

El uso de un paradigma pseudo-funcional no significa que los principios normales de nomenclatura deberían desaparecer. Las interfaces casi siempre deben nombrarse por lo que hacen , no por alguna idea sintáctica genérica. Si las funciones se colocan en una pila de deshacer, deben nombrarse UndoFunction. Si se invocan desde eventos de la GUI, deben nombrarse GUIEventHandler. Los amigos no dejan que los amigos perpetúen las convenciones de nombres erróneos.

Karl Bielefeldt
fuente
Procedureestá bien también Para el contexto, estoy desarrollando una biblioteca genérica que necesita manejar este tipo de "estructura".
superbob
18
Me gusta Procedurede mis días pascales. A Proceduretiene efectos secundarios, a Functionno. Como no devuelve un valor, lo único que podría hacer es tener un efecto secundario.
Spencer Rathbun
Podría estar inclinado a usar ProcedureRIR<T1,T2>para void proc(T1, int, T2), y del mismo modo para otros tipos, probablemente creando la mayoría de ellos a pedido en lugar de tratar de incluir todas las combinaciones posibles de tipos.
supercat
1
De hecho, la programación funcional real generalmente no fomenta la denominación de estilo húngaro. Esta es más la mentalidad del paradigma oo más que funcional.
slebetman
3
If the functions are placed into an undo stack, they should be named UndoFunction.Sin embargo, hay una diferencia entre nombrar la función y darle un tipo diferente. En estilo funcional que no genere un UndoFunctontipo porque ahora no se puede pasar a flip, curry, compose, filter, map, etc, en mi opinión de que es la verdadera razón de la decisión de Java para dar funciones diferentes con diferentes nombres arities es estúpida. Por supuesto, si vas a usar efectos secundarios, llámalo como sea; ya arrojaste la composición por la ventana y posiblemente tampoco estés usando funciones.
Doval
33

En el mundo de Java, se llama Runnable. En el mundo C #, se llama Action.

Pero, hay un nombre mejor que se adapta muy bien a una vista más amplia de las cosas.

La vista más amplia de las cosas llega más tarde, cuando decides que, además de tu interfaz funcional sin parámetros, también necesitas tener interfaces funcionales similares que acepten uno, dos o más argumentos, o que devuelvan un valor. Cuando eso suceda, querrá que los nombres de todas esas entidades sean isomorfos y correspondan entre sí.

Entonces, en Java, tengo mi propio conjunto de interfaces funcionales que llamo Procedures, definidas de la siguiente manera:

public interface Procedure
{
    void invoke();
}

public interface Procedure1<T1>
{
    void invoke( T1 argument1 );
}

... (te dan la imagen.)

Y también tengo un conjunto similar de interfaces llamado Functions, definido de manera similar, siendo el primer parámetro genérico el tipo de retorno:

public interface Function<R>
{
    R invoke();
}

public interface Function1<R,T1>
{
    R invoke( T1 argument1 );
}

Entonces, mi punto aquí es que Procedurees un muy buen nombre porque encaja perfectamente en una visión más amplia de las cosas. Si luego decide tener interfaces funcionales similares con métodos que aceptan argumentos o devuelven un valor, se encontrará con esto.

NOTA: Básicamente , estoy de acuerdo con la afirmación de Karl Bielefeldt de que "los principios de denominación normales [no] deben salir por la ventana" y que "las interfaces casi siempre deben nombrarse por lo que hacen, no por alguna idea sintáctica genérica". Pero tenga en cuenta que incluso él permite "casi siempre". A veces hay una necesidad de procedimientos y funciones (esencialmente anónimas), y eso es lo que pide el OP, y eso es lo que estoy respondiendo.

Enmienda 2017-11-10:

Usted podría preguntar, ¿por qué en Function1<R,T1>lugar de Function1<T1,R>? Podría ir en cualquier dirección, pero tengo preferencia por los valores de retorno a la izquierda porque me gusta seguir la convención de nomenclatura 'convertir-de' (destino-de-fuente) en lugar de 'convertir-a' (fuente-a -destinación). (Lo cual es más un accidente que una convención, en realidad, en el sentido de que lo más probable es que nadie lo haya pensado, porque si lo hubieran pensado, habrían llegado a la convención de 'conversión de'. )

Leí sobre esto en Joel Spolksy: hacer que el código incorrecto parezca incorrecto , es un artículo muy largo, que recomiendo leer en su totalidad, pero si desea saltar directamente al caso en cuestión, busque 'TypeFromType', pero para darle la TL; DR, la idea es que myint = intFromStr( mystr )es mucho mejor que myint = strToInt( mystr ), porque en el primer caso los nombres de los tipos están cerca de los valores asociados, por lo que puede ver fácilmente que 'int' coincide con 'int' y el 'str' coincide con el 'str'.

Entonces, por extensión, tiendo a ordenar las cosas en la forma en que aparecerán en el código.

Mike Nakis
fuente
1
Esta solución es realmente buena, parece aún más a prueba de balas que el propio Proveedor, Consumidor, BiFunction de Java, ..., porque todo se basa solo en dos conceptos. Me recuerda a la respuesta de @Karl Bielefeldt sobre " La elección de Java de hacerlo de esa manera con un nombre separado para cada arity [que] fue estúpido ". El único "inconveniente" es que no maneja tipos primitivos y sus combinaciones (cosas divertidas como DoubleToLongFunction, ToLongBiFunction, ...). Pero las primitivas son otra preocupación ...
superbob
Si. Básicamente, una vez que comienza a reemplazar los genéricos por primitivos, esto significa que realmente le importa el rendimiento, por lo que está bien si se desvía de la convención presentada aquí y usa nombres altamente personalizados para una mejora del rendimiento altamente personalizada.
Mike Nakis
1
Si pudiera aceptar una segunda respuesta, elegiría la suya gracias a las sugerencias del Procedimiento N , Función N. Todavía lo voté.
superbob
¿Por qué no es así Function1<T1, R>?
ErikE
@ErikE esa es una muy buena pregunta, y modifiqué mi publicación para responderla.
Mike Nakis
18

¿Por qué no Command? Dado que no toma datos y no devuelve datos, pero suponiendo que llamarlo causa algún efecto (de lo contrario, sería bastante inútil en realidad), imagino que eso es aproximadamente lo único que puede hacer: disparar una acción, hacer que algo suceda.

Hablando de eso, también hay un Actiondelegado genérico en .NET. A diferencia de Java, Consumerpuede tomar de 0 a 16 argumentos; en otras palabras, la versión más simple de la misma no requiere nada; vea MSDN .

Y dado que el nombre no implica que haya algo para "consumir", también parece una buena elección de nombre.

Konrad Morawski
fuente
1
Commandes bueno. Se puede confundir con el patrón de Comando, pero podría ser la solución.
superbob
77
Me gusta Actionmás que Command. Un comando suena más como algo que se recibe y evalúa, mientras que se ejecuta una acción por sus efectos secundarios.
Bergi
77
Umm ... ¿cómo puede no ser un patrón de Comando? ¡Has construido exactamente la entidad Comando! Incluso tiene un execute()método tradicionalmente nombrado . 0_o '
hijarian
1
No me gusta la sugerencia de Acción, ya que es una interfaz Swing común (y buena). El comando es razonable.
user949300
@ user949300, pero depende del contexto: Java es un gran mundo, soy un desarrollador de Android (ahora) y no tengo idiosincrasias relacionadas con J2EE;) Estoy de acuerdo, por supuesto, que la convención de nomenclatura elegida no debería entrar en conflicto con el que usa tu framework.
Konrad Morawski