Jak nazywa się funkcja, która nie przyjmuje argumentów i nic nie zwraca? [Zamknięte]

80

W java.util.functionpakiecie Java 8 mamy:

  • Funkcja : Bierze jeden argument, daje jeden wynik.
  • Konsument : bierze jeden argument, nic nie produkuje.
  • Dostawca : Nie bierze argumentu, daje jeden wynik.
  • ... : Inne sprawy obsługujące operacje podstawowe, 2 argumenty itp.

Ale muszę sobie poradzić z przypadkiem „ nie bierze argumentu, nic nie produkuje ”.

W tym nie ma nic java.util.functionnal.

Pytanie brzmi:

Jak nazywa się „ funkcja, która nie przyjmuje argumentów i niczego nie zwraca ”?

W Javie 8 jego definicją byłoby:

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

Executor już istnieje i ma inny cel: „ Obiekt, który wykonuje przesłane zadania Runnable ”. Podpis nie pasuje ( execute(Runnable):void) i nie jest nawet funkcjonalnym interfejsem .

Runnable istnieje, ale jest silnie powiązany z kontekstem wątków:

  • Pakiet java.langnie jest java.util.function.
  • Jawadoc stwierdza: „ Interfejs Runnable powinien być implementowany przez każdą klasę, której instancje mają być wykonywane przez wątek ”.
  • Nazwa „Runnable” sugeruje trochę działającego kodu w wątku.
superbob
źródło
28
„Ale nie ma nic dla„ Nie bierze argumentów, nic nie produkuje. ”” - Runnable ?
user11153
11
Myślę, że javadoc for Runnablejest w tym momencie nieaktualny, ponieważ Runnable jest również używany przez inne klasy niż Thread( Executorna przykład).
SpaceTrucker
13
@superbob To nie znaczy, że RunnableS może być tylko .run()przez Threadsekundę. W rzeczywistości są one bardzo często używane dokładnie do celu opisanego w pytaniu
blgt
5
@ superbob To był jego pierwotny cel, ale od wersji Java 8 został „zmodernizowany” jako interfejs funkcjonalny. Właśnie dlatego nic nie znalazłeś w java.util.function pakiecie.
user11153,
5
Semi-Snark: ImpureFuntion, ponieważ z pewnością opiera się tylko na efektach ubocznych, w przeciwnym razie nie jest to możliwe. ( en.wikipedia.org/wiki/Pure_function#Impure_functions ) Więcej poważnie: Tryb rozkazujący (zrób coś), który przynajmniej odpowiada semantyce void execute ();
Kristian H

Odpowiedzi:

71

Wybór Javy, aby zrobić to w ten sposób z osobną nazwą dla każdego ariana, był głupi. Nie jest to warte naśladowania. Jeśli jednak musisz zachować spójność lub piszesz bardzo ogólny kod biblioteki, sugestie Konrada są dobre. Mogę rzucić Procedurew pierścień.

Użycie pseudo-funkcjonalnego paradygmatu nie oznacza, że ​​normalne zasady nazewnictwa powinny wyjść z okna. Interfejsy należy prawie zawsze nazywać po tym, co robią , a nie po ogólnym pomyśle syntaktycznym. Jeśli funkcje zostaną umieszczone w stosie cofania, należy je nazwać UndoFunction. Jeśli są wywoływane ze zdarzeń GUI, należy je nazwać GUIEventHandler. Przyjaciele nie pozwalają przyjaciołom utrwalać złych konwencji nazewnictwa.

Karl Bielefeldt
źródło
Procedureteż jest w porządku. W kontekście opracowuję bibliotekę ogólną, która musi obsługiwać tego rodzaju „strukturę”.
superbob
18
Lubię Procedureod moich pascal dni. A Procedurema skutki uboczne, a Functionnie. Ponieważ nie zwracasz wartości, jedyne, co może zrobić, to mieć efekt uboczny.
Spencer Rathbun,
I może być skłonny do korzystania ProcedureRIR<T1,T2>z void proc(T1, int, T2), a także dla innych typów - prawdopodobnie tworząc większość z nich na żądanie zamiast próbować dopchać w każdej możliwej kombinacji typów.
supercat
1
Rzeczywiście, rzeczywiste programowanie funkcjonalne zasadniczo nie zachęca do nazywania stylu węgierskiego. To bardziej mentalność paradygmatu z oo niż funkcjonalna.
slebetman
3
If the functions are placed into an undo stack, they should be named UndoFunction.Istnieje jednak różnica między nazwaniem funkcji a nadaniem jej innego typu. W funkcjonalnym stylu nie spowodowałoby UndoFunctontyp bo teraz nie można przekazać go do flip, curry, compose, filter, map, itp w moim przekonaniu , że jest prawdziwym powodem decyzji Java dać funkcje z różnych arities różne nazwy jest głupie. Oczywiście, jeśli zamierzasz stosować efekty uboczne, nazwij to jakkolwiek; już wyrzuciłeś kompozycję przez okno i prawdopodobnie też nie używasz funkcji.
Doval
33

W świecie Java nazywa się to Runnable. W świecie C # nazywa się to Action.

Ale istnieje lepsza nazwa, która ładnie pasuje do szerszego widoku rzeczy.

Szerszy widok rzeczy pojawia się później, gdy zdecydujesz, że oprócz twojego pozbawionego parametrów pustego interfejsu funkcjonalnego potrzebujesz także podobnych interfejsów funkcjonalnych, które akceptują jeden, dwa lub więcej argumentów lub zwracają wartość. Kiedy tak się stanie, będziesz chciał, aby nazwy wszystkich tych bytów były izomorficzne i korespondowały ze sobą.

Tak więc w Javie mam własny zestaw interfejsów funkcjonalnych, które nazywam Procedures, zdefiniowane w następujący sposób:

public interface Procedure
{
    void invoke();
}

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

... (Dostajesz obraz.)

Mam również podobny zestaw interfejsów o nazwie Functions, zdefiniowany w podobny sposób, przy czym pierwszym parametrem ogólnym jest typ zwracany:

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

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

Chodzi mi o to, że Procedurejest to bardzo dobre imię, ponieważ ładnie pasuje do szerszego widoku rzeczy. Jeśli później zdecydujesz się na podobne interfejsy funkcjonalne z metodami, które akceptują argumenty lub zwracają wartość, natkniesz się na to.

UWAGA: Zasadniczo zgadzam się z twierdzeniem Karla Bielefeldta, że ​​„normalne zasady nazewnictwa powinny [nie] wychodzić z okna” i że „interfejsy należy prawie zawsze nazywać po tym, co robią, a nie po ogólnym pomyśle syntaktycznym”. Pamiętaj jednak, że nawet on pozwala na „prawie zawsze”. Czasami potrzebne są (zasadniczo anonimowe) procedury i funkcje, i właśnie o to prosi OP, i na to odpowiadam.

Poprawka 2017-11-10:

Możesz zapytać, dlaczego Function1<R,T1>zamiast Function1<T1,R>? Może pójść w obie strony, ale preferuję zwracanie wartości po lewej stronie, ponieważ lubię stosować konwencję nazewnictwa „konwersja z” (miejsce docelowe z źródła) w przeciwieństwie do „konwersji do” -destination) konwencja. (Co jest bardziej wypadkiem niż konwencją, w rzeczywistości w tym sensie, że najprawdopodobniej nikt nigdy nie zastanawiał się nad tym, ponieważ gdyby w ogóle się nad tym zastanowili, doszliby do konwencji o nawróceniu. )

Przeczytałem o tym w Joel Spolksy - Sprawianie, że zły kod wygląda źle , jest to bardzo długi artykuł, który polecam przeczytać w całości, ale jeśli chcesz przejść bezpośrednio do omawianej sprawy, wyszukaj „TypeFromType”, ale aby dać TL; DR, pomysł jest o myint = intFromStr( mystr )wiele lepszy niż myint = strToInt( mystr ), ponieważ w pierwszym przypadku nazwy typów są zbliżone do powiązanych wartości, dzięki czemu można łatwo zobaczyć, że „int” pasuje do „int” i „str” pasuje do „str”.

Tak więc, przez rozszerzenie, mam tendencję do porządkowania rzeczy w taki sposób, w jaki będą wyglądały w kodzie.

Mike Nakis
źródło
1
To rozwiązanie jest naprawdę dobre, wydaje się nawet bardziej kuloodporne niż własny dostawca, konsument, biFunkcja Javy ..., ponieważ wszystko sprowadza się tylko do dwóch koncepcji. Przypomina mi to odpowiedź @Karl Bielefeldt na temat „ wyboru Javy, aby zrobić to w ten sposób, z osobną nazwą dla każdej arity, która była głupia ”. Jedynym minusem jest to, że nie obsługuje prymitywnych typów i ich kombinacji (zabawne rzeczy, takie jak DoubleToLongFunction, ToLongBiFunction, ...). Ale prymitywy to kolejny problem ...
superbob
Tak. Zasadniczo, kiedy zaczniesz zastępować leki generyczne prymitywami, oznacza to, że naprawdę zależy ci na wydajności, więc możesz odstąpić od przedstawionej tu konwencji i użyć wysoce spersonalizowanych nazw w celu bardzo niestandardowej poprawy wydajności.
Mike Nakis,
1
Gdybym mógł zaakceptować drugą odpowiedź, wybrałbym twoją dzięki sugestiom Procedury N , Funkcji N. Nadal go głosowałem.
superbob
Dlaczego tak nie Function1<T1, R>jest
ErikE,
@ErikE to bardzo dobre pytanie i poprawiłem swój post, aby na nie odpowiedzieć.
Mike Nakis,
18

Dlaczego nie Command? Biorąc pod uwagę, że nie wymaga danych i nie zwraca żadnych danych, ale zakładając, że wywołanie go powoduje jakiś efekt (w przeciwnym razie byłoby to raczej bezcelowe), wyobrażam sobie, że jest to z grubsza jedyna rzecz, jaką może zrobić - uruchomić akcję, sprawić, by coś się stało.

Mówiąc o tym, istnieje również ogólny Actiondelegat w .NET. W przeciwieństwie do Javy Consumermoże zająć od 0 do 16 argumentów; innymi słowy, najprostsza wersja tego nie wymaga - patrz MSDN .

A ponieważ nazwa nie sugeruje, że ma się co „konsumować”, wydaje się, że to dobry wybór.

Konrad Morawski
źródło
1
Commandjest dobry. Można go pomylić ze schematem poleceń, ale może to być rozwiązanie.
superbob
7
Lubię Actionwięcej niż Command. Polecenie brzmi bardziej jak coś, co jest odbierane i oceniane, podczas gdy akcja jest wykonywana dla jej skutków ubocznych.
Bergi,
7
Umm ... jak to nie może być wzór poleceń? Zbudowałeś dokładnie encję Dowodzenia! Ma nawet tradycyjnie nazwaną execute()metodę. 0_o '
hijarian
1
Nie lubię sugestii działania, ponieważ jest to powszechny (i dobry) interfejs Swing. Dowodzenie jest rozsądne.
user949300
@ user949300, ale zależy to od kontekstu - Java to duży świat, który widzisz, jestem programistą Androida (teraz) i nie mam żadnych osobliwości związanych z J2EE;) Zgadzam się oczywiście, że wybrana konwencja nazewnictwa nie powinna kolidować z tym, którego używa twój framework.
Konrad Morawski