Quel est le nom d'une fonction qui ne prend aucun argument et ne retourne rien? [fermé]

82

Dans le java.util.functionpackage Java 8 , nous avons:

  • Fonction : Prend un argument, produit un résultat.
  • Consommateur : prend un argument, ne produit rien.
  • Fournisseur : ne prend pas d'argument, produit un résultat.
  • ... : Autres cas traitant des primitives, 2 arguments, etc ...

Mais je dois gérer le cas " ne prend pas d'argument, ne produit rien ".

Il n'y a rien pour cela dans java.util.functionnal.

Donc, la question est:

Quel est le nom de " une fonction qui ne prend aucun argument et ne retourne rien "?

En Java 8, sa définition serait:

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

Executor existe déjà et a un autre objectif: " Un objet qui exécute les tâches exécutables soumises ". La signature ne correspond pas ( execute(Runnable):void) et n'est même pas une interface fonctionnelle .

Runnable existe, mais il est fortement lié au contexte de threading:

  • Le paquet est java.lang, non java.util.function.
  • Le javadoc indique: " L'interface Runnable doit être implémentée par toute classe dont les instances sont destinées à être exécutées par un thread ".
  • Le nom "Runnable" suggère un code courant dans un thread.
superbob
la source
28
"Mais il n'y a rien pour" Ne prend aucun argument, ne produit rien. "" - Runnable ?
user11153
11
Je pense que le javadoc pour Runnableest obsolète à ce stade, car un Runnable est également utilisé par d'autres classes que Thread( Executorpar exemple).
SpaceTrucker
13
@superbob Cela ne veut pas dire que Runnables ne peut être que .run()par Threads. En fait, ils sont très couramment utilisés exactement dans le but décrit dans la question
blgt
5
@sererbob C'était son objectif initial, mais depuis Java 8, il a été "transformé" en interface fonctionnelle. C'est pourquoi vous n'avez rien trouvé dans le java.util.function paquet.
user11153
5
Semi-Snark: ImpureFuntion, car il ne repose que sur les effets secondaires, sinon c'est un non-op. ( en.wikipedia.org/wiki/Pure_function#Impure_functions ) Plus de Seriosuly: Impératif (faire quelque chose), qui correspondrait au moins à la sémantique de void execute ();
Kristian H

Réponses:

71

Le choix de Java de le faire de cette façon avec un nom distinct pour chaque arité était stupide. Ce n'est pas exactement la peine d'émuler. Toutefois, si vous devez le faire par souci de cohérence ou si vous écrivez un code de bibliothèque très générique, les suggestions de Konrad sont bonnes. Je pourrais jeter Proceduredans le ring.

L'utilisation d'un paradigme pseudo-fonctionnel ne signifie pas que les principes de dénomination normaux doivent disparaître. Les interfaces doivent presque toujours être nommées d'après ce qu'elles font , et non d'après une idée syntaxique générique. Si les fonctions sont placées dans une pile d'annulation, elles doivent être nommées UndoFunction. S'ils sont appelés à partir d'événements graphiques, ils doivent être nommés GUIEventHandler. Les amis ne laissent pas leurs amis perpétuer les conventions de dénomination.

Karl Bielefeldt
la source
Procedureest bien aussi. Pour le contexte, je développe une bibliothèque générique qui doit gérer ce type de "structure".
superbob
18
J'aime Proceduredepuis mes jours pascal. Un Procedurea des effets secondaires, un Functionpas. Puisque vous ne renvoyez pas de valeur, la seule chose à faire est d’avoir un effet secondaire.
Spencer Rathbun
Je pourrais être enclin à utiliser ProcedureRIR<T1,T2>pour void proc(T1, int, T2), et de la même manière, d’autres types - probablement en créant la plupart d’entre eux à la demande plutôt que d’essayer de créer toutes les combinaisons possibles de types.
Supercat
1
En effet, la programmation fonctionnelle réelle n’encourage généralement pas la dénomination à la hongroise. C'est plus la mentalité du paradigme oo que fonctionnelle.
Slebetman
3
If the functions are placed into an undo stack, they should be named UndoFunction.Cependant, il existe une différence entre nommer la fonction et lui attribuer un type différent. Dans un style fonctionnel , vous ne créeraient pas un UndoFunctongenre parce que maintenant vous ne pouvez pas passer à flip, curry, compose, filter, map, etc. À mon avis qui est la vraie raison de la décision de Java pour donner des fonctions différentes avec des noms différents arités est stupide. Bien sûr, si vous utilisez des effets secondaires, appelez-les comme vous le souhaitez. vous avez déjà jeté la composition par la fenêtre et vous n'utilisez probablement pas non plus de fonctions.
Doval
33

Dans le monde java, cela s'appelle Runnable. Dans le monde C #, cela s'appelle Action.

Mais, il existe un meilleur nom qui s’intègre parfaitement dans une vision plus large des choses.

La vue d'ensemble des choses vient plus tard, lorsque vous décidez qu'en plus de votre interface fonctionnelle void sans paramètre, vous devez également disposer d'interfaces fonctionnelles similaires acceptant un, deux ou plusieurs arguments, ou renvoyant une valeur. Lorsque cela se produira, vous voudrez que les noms de toutes ces entités soient isomorphes et correspondants les uns aux autres.

Donc, en Java, j’ai mon propre ensemble d’interfaces fonctionnelles que j’appelle Procedures, défini comme suit:

public interface Procedure
{
    void invoke();
}

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

... (vous avez l'image.)

Et j’ai aussi un ensemble similaire d’interfaces appelé Functions, défini de la même façon, le premier paramètre générique étant le type de retour:

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

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

Donc, ce que je veux dire, c'est que Procedurec'est un très bon nom, car cela correspond parfaitement à une vision plus large des choses. Si vous décidez ultérieurement de disposer d'interfaces fonctionnelles similaires avec des méthodes acceptant les arguments ou renvoyant une valeur, vous devrez le rencontrer.

NOTE: Je essentiellement suis d' accord avec l'affirmation de Karl Bielefeldt que «principes de nommage normaux doivent [pas] sortir par la fenêtre » et que « Interfaces doivent presque toujours être nomméesaprès ce qu'ils font, pas après une idée syntaxique générique. » Mais notez que même il permet "presque toujours". Parfois, des procédures et des fonctions (essentiellement anonymes) sont nécessaires, et c'est ce que demande le PO, et c'est ce à quoi je réponds.

Amendement 2017-11-10:

Vous pourriez demander, pourquoi Function1<R,T1>au lieu de Function1<T1,R>? Cela peut aller dans les deux sens, mais j'ai une préférence pour les valeurs de retour sur la gauche car j'aime bien suivre la convention de dénomination 'convertir à partir de (destination-de-source) par opposition à la conversion' à-convertir '(source à -destination) convention. (Ce qui est plus un accident qu'une convention, en réalité, en ce sens que probablement personne n’y a jamais pensé, parce que s’ils y avaient pensé du tout, ils seraient parvenus à la convention du "converti de". )

J'ai lu à ce sujet dans Joel Spolksy - Making Wrong Code Look Wrong , il s'agit d'un très long article, que je recommande de lire dans son intégralité, mais si vous souhaitez passer directement à l'affaire, recherchez 'TypeFromType', mais vous donne le TL; DR, l’idée est que myint = intFromStr( mystr )c’est beaucoup mieux que myint = strToInt( mystr ), parce que dans le premier cas, les noms des types sont proches des valeurs associées, de sorte que vous pouvez facilement voir que le 'int' correspond au 'int' et le 'str' correspond au 'str'.

Donc, par extension, j'ai tendance à ordonner les choses de la manière dont elles vont apparaître dans le code.

Mike Nakis
la source
1
Cette solution est vraiment bonne, elle semble encore plus résistante que le fournisseur, consommateur, BiFunction, ... de Java, car elle ne contient que deux concepts. Cela me rappelle la réponse de @Karl Bielefeldt sur " le choix de Java de le faire de cette façon avec un nom distinct pour chaque arité [qui] était stupide ". Le seul inconvénient est qu'il ne gère pas les types primitifs et leurs combinaisons (des éléments amusants comme DoubleToLongFunction, ToLongBiFunction, ...). Mais les primitifs sont une autre préoccupation ...
superbob
Oui. Fondamentalement, dès que vous commencez à remplacer les génériques par des primitives, cela signifie que vous vous souciez vraiment de la performance. Vous pouvez donc vous écarter de la convention présentée ici et utiliser des noms hautement personnalisés pour une amélioration de la performance hautement personnalisée.
Mike Nakis
1
Si je pouvais accepter une deuxième réponse, je choisirais la vôtre grâce aux suggestions de Procédure N , Fonction N. Je l'ai toujours voté.
Superbe
Pourquoi n'est-ce pas Function1<T1, R>?
ErikE
@ ErikE c'est une très bonne question, et j'ai modifié mon post pour y répondre.
Mike Nakis
18

Pourquoi ne pas Command? Étant donné que cela ne prend aucune donnée et ne renvoie aucune donnée, mais en supposant que l'appel provoque un effet (sinon ce serait plutôt inutile), j'imagine que c'est à peu près la seule chose à faire: déclencher une action, faire bouger les choses.

En parlant de cela, il existe également un Actiondélégué générique dans .NET. Contrairement à Java, Consumeril peut prendre de 0 à 16 arguments. en d'autres termes, la version la plus simple ne prend rien - voir MSDN .

Et puisque le nom n'implique pas qu'il y ait quoi que ce soit à "consommer", cela semble également être un bon choix de nom.

Konrad Morawski
la source
1
Commandest bon. Cela peut être confondu avec le modèle de commande mais cela pourrait être la solution.
superbob
7
J'aime Actionplus que Command. Une commande ressemble davantage à quelque chose qui est reçu et évalué, alors qu'une action est exécutée pour ses effets secondaires.
Bergi
7
Umm ... comment cela ne peut-il pas être un motif de commande? Vous avez construit exactement l'entité Command! Il a même traditionnellement nommé execute()méthode. 0_o '
hijarian
1
N'aimez pas la suggestion d'action, car c'est une interface Swing commune (et bonne). La commande est raisonnable.
user949300
@ user949300 mais cela dépend du contexte - Java est un monde gigantesque, je suis un développeur Android (à présent) et je n'ai aucune idiosyncrasie liée à J2EE;) Je conviens, bien entendu, que la convention de dénomination choisie ne devrait pas entrer en conflit avec celui que votre framework utilise.
Konrad Morawski