Qual è il nome di una funzione che non accetta argomenti e non restituisce nulla? [chiuso]


80

Nel java.util.functionpacchetto di Java 8 abbiamo:

  • Funzione : accetta un argomento, produce un risultato.
  • Consumatore : accetta un argomento, non produce nulla.
  • Fornitore : non accetta argomenti, produce un risultato.
  • ... : altri casi che trattano primitivi, 2 argomenti, ecc ...

Ma devo gestire il caso " non prende argomenti, non produce nulla ".

Non c'è niente per questo in java.util.functionnal.

Quindi, la domanda è:

Qual è il nome di " una funzione che non accetta argomenti e non restituisce nulla "?

In Java 8, la sua definizione sarebbe:

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

Executor esiste già e ha un altro scopo: " Un oggetto che esegue attività eseguibili inviate ". La firma non corrisponde ( execute(Runnable):void) e non è nemmeno un'interfaccia funzionale .

Eseguibile esiste, ma è fortemente collegato al contesto di threading:

  • Il pacchetto java.langnon lo è java.util.function.
  • Il javadoc afferma: " L'interfaccia Runnable dovrebbe essere implementata da qualsiasi classe le cui istanze sono destinate ad essere eseguite da un thread ".
  • Il nome "Runnable" suggerisce un codice in esecuzione all'interno di un thread.

28
"Ma non c'è niente per" Non prende argomenti, non produce nulla "" - Runnable ?
user11153

11
Penso che javadoc per Runnablesia obsoleto a questo punto, perché un Runnable viene utilizzato anche da classi diverse da Thread( Executorad esempio).
SpaceTrucker,

13
@superbob Ciò non significa che Runnables possa essere solo .run()per Threads. In realtà sono molto comunemente usati esattamente per lo scopo descritto nella domanda
blgt

5
@superbob Quello era il suo scopo iniziale, ma da quando Java 8 è stato "adattato" come interfaccia funzionale. Quindi questo è il motivo per cui non hai trovato nulla nel java.util.function pacchetto.
user11153

5
Semi-Snark: ImpureFuntion perché sicuramente si basa solo su effetti collaterali, altrimenti è una no-op. ( en.wikipedia.org/wiki/Pure_function#Impure_functions ) Altro Seriosuly: Imperative (fai qualcosa), che almeno corrisponderebbe alla semantica di void execute ();
Kristian H,

Risposte:


71

La scelta di Java di farlo in quel modo con un nome separato per ogni arità era stupida. Non vale esattamente la pena di emularlo. Tuttavia, se è necessario per motivi di coerenza o se stai scrivendo un codice di libreria molto generico, i suggerimenti di Konrad sono validi. Potrei buttarmi Proceduresul ring.

L'uso di un paradigma pseudo-funzionale non significa che i normali principi di denominazione dovrebbero uscire dalla finestra. Le interfacce dovrebbero quasi sempre avere il nome di quello che fanno , non dopo qualche idea sintattica generica. Se le funzioni vengono inserite in uno stack di annullamento, devono essere denominate UndoFunction. Se vengono chiamati dagli eventi della GUI, devono essere nominati GUIEventHandler. Gli amici non consentono agli amici di perpetuare convenzioni di denominazione sbagliate.


Procedureva anche bene. Per il contesto, sto sviluppando una libreria generica che deve gestire questo tipo di "struttura".
superbob

18
Mi piace Proceduredai miei giorni pasquali. A Procedureha effetti collaterali, a Functionno. Dato che non restituisci un valore, l'unica cosa che potrebbe fare è avere un effetto collaterale.
Spencer Rathbun,

Potrei essere propenso a usarlo ProcedureRIR<T1,T2>per void proc(T1, int, T2), e allo stesso modo per altri tipi - probabilmente creando la maggior parte di essi su richiesta piuttosto che cercare di stipare in ogni possibile combinazione di tipi.
supercat

1
In effetti, la vera programmazione funzionale generalmente non incoraggia la denominazione in stile ungherese. Questa è più la mentalità del paradigma oo piuttosto che funzionale.
Slebetman,

3
If the functions are placed into an undo stack, they should be named UndoFunction.C'è una differenza tra nominare la funzione e dargli un tipo diverso però. In stile funzionale non sarebbe creare un UndoFunctontipo perché ora non è possibile passare a flip, curry, compose, filter, map, ecc A mio parere , che è la vera ragione per la decisione di Java per dare funzioni con diversi nomi diversi arietà è stupido. Certo, se hai intenzione di usare effetti collaterali, chiamalo comunque; hai già gettato la composizione fuori dalla finestra e probabilmente non stai nemmeno usando le funzioni.
Doval,

33

Nel mondo Java, si chiama Runnable. Nel mondo C #, si chiama Action.

Ma esiste un nome migliore che ben si adatta a una visione più ampia delle cose.

La visione più ampia delle cose arriva più tardi, quando decidi che oltre alla tua interfaccia funzionale vuota senza parametri devi anche avere interfacce funzionali simili che accettano uno, due o più argomenti, o che restituiscono un valore. Quando ciò accade, vorrai che i nomi di tutte quelle entità siano isomorfi e corrispondenti tra loro.

Quindi, in Java, ho il mio set di interfacce funzionali che chiamo Procedures, definito come segue:

public interface Procedure
{
    void invoke();
}

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

... (ottieni l'immagine.)

E ho anche un set simile di interfacce chiamato Functions, definito in modo simile, con il primo parametro generico che è il tipo restituito:

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

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

Quindi, il mio punto qui è che Procedureè un ottimo nome perché si adatta perfettamente a una visione più ampia delle cose. Se in seguito decidi di avere interfacce funzionali simili con metodi che accettano argomenti o restituiscono un valore, ti imbatterai in questo.

NOTA: concordo sostanzialmentecon l'affermazione di Karl Bielefeldt secondo cui "i normali principi di denominazione dovrebbero [non] uscire dalla finestra" e che "Le interfacce dovrebbero quasi sempre avere il nome di ciò che fanno, non dopo qualche idea sintattica generica". Ma nota che anche lui permette "quasi sempre". A volte sono necessarie procedure e funzioni (essenzialmente anonime), ed è quello che l'OP sta chiedendo, ed è quello a cui sto rispondendo.

Emendamento 10-11-2017:

Potresti chiedere, perché Function1<R,T1>invece di Function1<T1,R>? Potrebbe andare in entrambi i modi, ma ho una preferenza per i valori di ritorno a sinistra perché mi piace seguire la convenzione di denominazione 'convert-from' (destination-from-source) rispetto alla 'convert-to' (source-to -destinazione) convenzione. (Che è più un incidente che una convenzione, davvero, nel senso che molto probabilmente nessuno ci ha mai pensato, perché se ci avessero pensato, sarebbero arrivati ​​alla convenzione "convertiti da". )

Ho letto di questo in Joel Spolksy - Far sembrare sbagliato il codice sbagliato , è un articolo molto lungo, che consiglio di leggere nella sua interezza, ma se vuoi saltare direttamente al caso in esame, cerca "TypeFromType", ma per darti il ​​TL; DR, l'idea è myint = intFromStr( mystr )molto meglio di myint = strToInt( mystr ), perché nel primo caso i nomi dei tipi sono vicini ai valori associati, quindi puoi facilmente vedere che 'int' corrisponde a 'int' e lo "str" ​​corrisponde allo "str".

Quindi, per estensione, tendo a ordinare le cose nel modo in cui appariranno nel codice.


1
Questa soluzione è davvero buona, sembra persino più a prova di proiettile rispetto al proprio fornitore, consumatore, BiFunction di java, ... perché stabilisce tutto solo in due concetti. Mi ricorda la risposta di @Karl Bielefeldt sulla " scelta di Java di farlo in quel modo con un nome separato per ogni arità [che] era stupida ". L'unico "aspetto negativo" è che non gestisce i tipi primitivi e le loro combinazioni (cose divertenti come DoubleToLongFunction, ToLongBiFunction, ...). Ma le primitive sono un'altra preoccupazione ...
superbob

Sì. Fondamentalmente, una volta che inizi a sostituire i generici con i primitivi, questo significa che ti preoccupi davvero delle prestazioni, quindi va bene se ti allontani dalla convenzione qui presentata e usi nomi altamente personalizzati per un miglioramento delle prestazioni altamente personalizzato.
Mike Nakis,

1
Se potessi accettare una seconda risposta, sceglierei la tua grazie ai suggerimenti Procedura N , Funzione N. L'ho ancora votato.
superbob

Perché no Function1<T1, R>?
ErikE

@ErikE questa è un'ottima domanda e ho modificato il mio post per rispondere.
Mike Nakis,

18

Perché no Command? Dato che non prende dati e non restituisce dati, ma supponendo che chiamarlo causi qualche effetto (altrimenti sarebbe piuttosto inutile davvero), immagino che sia all'incirca l'unica cosa che può fare: sparare un'azione, far accadere qualcosa.

A proposito, c'è anche un Actiondelegato generico in .NET. A differenza di Java, Consumerpuò richiedere da 0 a 16 argomenti; in altre parole, la versione più semplice non ne accetta nessuna - vedi MSDN .

E poiché il nome non implica che ci sia qualcosa da "consumare", sembra anche una buona scelta per il nome.


1
Commandè buono. Può essere confuso con il modello di comando ma potrebbe essere la soluzione.
superbob

7
Mi piace di Actionpiù Command. Un comando suona più come qualcosa che viene ricevuto e valutato, mentre un'azione viene eseguita per i suoi effetti collaterali.
Bergi,

7
Umm ... come può non essere un modello di comando? Hai costruito esattamente l'entità Comando! Ha anche un execute()metodo chiamato tradizionalmente . 0_o '
hijarian

1
Non mi piace il suggerimento di Action, poiché questa è un'interfaccia Swing comune (e buona). Il comando è ragionevole.
user949300

@ user949300 ma dipende dal contesto - Java è un grande mondo, vedi, sono uno sviluppatore Android (ora) e non ho idiosincrasie relative a J2EE;) Sono d'accordo, ovviamente, che la convenzione di denominazione scelta non dovrebbe scontrarsi con quello utilizzato dal framework.
Konrad Morawski,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.