Apa nama fungsi yang tidak mengambil argumen dan tidak menghasilkan apa-apa? [Tutup]

80

Dalam java.util.functionpaket Java 8 , kami memiliki:

  • Fungsi : Mengambil satu argumen, menghasilkan satu hasil.
  • Konsumen : Mengambil satu argumen, tidak menghasilkan apa-apa.
  • Pemasok : Tanpa argumen, menghasilkan satu hasil.
  • ... : Kasus lain yang menangani primitif, 2 argumen, dll ...

Tetapi saya perlu menangani kasus " tidak perlu argumen, tidak menghasilkan apa-apa ".

Tidak ada dalam ini java.util.functionnal.

Jadi, pertanyaannya adalah:

Apa nama ' fungsi yang tidak mengambil argumen dan tidak menghasilkan apa - apa '?

Di Java 8, definisinya adalah:

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

Eksekutor sudah ada dan memiliki tujuan lain: " Objek yang mengeksekusi tugas Runnable yang diajukan ". Tanda tangan tidak cocok ( execute(Runnable):void) dan bahkan bukan antarmuka fungsional .

Runnable ada, tetapi sangat terkait dengan konteks threading:

  • Paketnya java.langbukan java.util.function.
  • Javadoc menyatakan: " Antarmuka Runnable harus diimplementasikan oleh kelas mana pun yang instance-nya dimaksudkan untuk dieksekusi oleh utas ".
  • Nama "Runnable" menyarankan beberapa kode yang berjalan di dalam utas.
superbob
sumber
28
"Tapi tidak ada apa-apa untuk" Tidak ada argumen, tidak menghasilkan apa-apa. "" - Runnable ?
user11153
11
Saya pikir javadoc untuk Runnablesudah usang pada saat ini, karena Runnable juga digunakan oleh kelas lain selain Thread( Executormisalnya).
SpaceTrucker
13
@superbob Itu tidak berarti bahwa Runnables hanya bisa .run()dengan Threads. Bahkan mereka sangat umum digunakan untuk tujuan yang dijelaskan dalam pertanyaan
blgt
5
@superbob Itulah tujuan awalnya, tetapi karena Java 8 itu "dipasang" sebagai antarmuka fungsional. Jadi ini sebabnya Anda tidak menemukan apa pun dalam java.util.function paket.
user11153
5
Semi-Snark: ImpureFuntion karena itu pasti hanya bergantung pada efek samping, jika tidak itu adalah no-op. ( en.wikipedia.org/wiki/Pure_function#Impure_functions ) Lebih Banyak Seriosuly: Imperatif (melakukan sesuatu), yang setidaknya akan cocok dengan semantik eksekusi batal ();
Kristian H

Jawaban:

71

Pilihan Jawa untuk melakukannya dengan nama yang terpisah untuk setiap kegiatan adalah bodoh. Ini tidak layak ditiru. Namun, jika Anda harus demi konsistensi, atau jika Anda sedang menulis kode perpustakaan yang sangat umum, saran Konrad baik. Saya mungkin melempar Procedureke atas ring.

Menggunakan paradigma pseudo-fungsional tidak berarti prinsip penamaan yang normal harus keluar jendela. Antarmuka hampir selalu dinamai sesuai dengan apa yang mereka lakukan , bukan setelah beberapa ide sintaksis generik. Jika fungsi ditempatkan ke dalam tumpukan undo, mereka harus dinamai UndoFunction. Jika mereka dipanggil dari acara GUI, mereka harus dinamai GUIEventHandler. Teman tidak membiarkan teman mengabadikan konvensi penamaan yang buruk.

Karl Bielefeldt
sumber
Procedurejuga baik-baik saja. Untuk konteksnya, saya sedang mengembangkan perpustakaan umum yang perlu menangani "struktur" semacam ini.
superbob
18
Saya suka Proceduredari hari pascal saya. A Procedurememiliki efek samping, a Functiontidak. Karena Anda tidak mengembalikan nilai, satu-satunya hal yang bisa dilakukan adalah memiliki efek samping.
Spencer Rathbun
Saya mungkin cenderung menggunakan ProcedureRIR<T1,T2>untuk void proc(T1, int, T2), dan juga untuk jenis lain - mungkin membuat sebagian besar sesuai permintaan daripada mencoba menjejalkan dalam setiap kemungkinan kombinasi jenis.
supercat
1
Memang, pemrograman fungsional nyata umumnya tidak mendorong penamaan gaya Hongaria. Ini lebih merupakan mentalitas paradigma oo daripada fungsional.
slebetman
3
If the functions are placed into an undo stack, they should be named UndoFunction.Ada perbedaan antara penamaan fungsi dan memberikannya tipe yang berbeda. Dalam gaya fungsional Anda tidak akan membuat UndoFunctonjenis karena sekarang Anda tidak bisa lewat ke flip, curry, compose, filter, map, dll Menurut pendapat saya bahwa alasan sebenarnya keputusan Java untuk memberikan fungsi dengan arities berbeda nama yang berbeda adalah bodoh. Tentu saja, jika Anda akan menggunakan efek samping, sebut saja apa pun; Anda sudah membuang komposisi ke luar jendela dan Anda mungkin juga tidak menggunakan fungsi.
Doval
33

Di dunia java, ini disebut Runnable. Di dunia C #, itu disebut Action.

Tapi, ada nama yang lebih baik yang cocok dengan pandangan yang lebih luas.

Pandangan yang lebih besar tentang hal-hal datang kemudian, ketika Anda memutuskan bahwa selain antarmuka fungsional parameterless Anda juga perlu memiliki antarmuka fungsional serupa yang menerima satu, dua, atau lebih argumen, atau yang mengembalikan nilai. Ketika itu terjadi, Anda akan ingin nama-nama semua entitas itu menjadi isomorfik dan korespondensi satu sama lain.

Jadi, di Jawa, saya memiliki set sendiri antarmuka fungsional yang saya sebut Procedures, didefinisikan sebagai berikut:

public interface Procedure
{
    void invoke();
}

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

... (Anda mendapatkan fotonya.)

Dan saya juga memiliki seperangkat antarmuka yang sama yang disebut Functions, didefinisikan dengan cara yang sama, dengan parameter generik pertama adalah tipe pengembalian:

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

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

Jadi, maksud saya di sini adalah Procedurenama yang sangat bagus karena cocok dengan pandangan yang lebih luas. Jika nanti Anda memutuskan untuk memiliki antarmuka fungsional yang sama dengan metode yang menerima argumen atau mengembalikan nilai, Anda akan mengalami hal ini.

CATATAN: Saya pada dasarnya setuju dengan pernyataan Karl Bielefeldt bahwa "prinsip penamaan normal harus [tidak] keluar jendela" dan bahwa "Antarmuka hampir selalu diberi nama sesuai dengan apa yang mereka lakukan, bukan setelah beberapa ide sintaksis generik." Tetapi perhatikan bahwa bahkan ia mengizinkan "hampir selalu". Kadang-kadang ada kebutuhan untuk (dasarnya anonim) prosedur dan fungsi, dan itulah yang diminta OP, dan itulah yang saya jawab.

Amandemen 2017-11-10:

Anda mungkin bertanya, mengapa Function1<R,T1>bukan Function1<T1,R>? Itu bisa berjalan baik, tetapi saya memiliki preferensi untuk mengembalikan nilai di sebelah kiri karena saya ingin mengikuti konvensi penamaan 'convert-from' (destination-from-source) sebagai lawan dari 'convert-to' (source-to) -destinasi) konvensi. (Yang lebih merupakan kecelakaan daripada sebuah konvensi, sungguh, dalam arti bahwa kemungkinan besar, tidak ada yang pernah memikirkannya, karena jika mereka memikirkannya sama sekali mereka akan tiba di konvensi 'convert-from'. )

Saya membaca tentang ini di Joel Spolksy - Membuat Kode yang Salah Terlihat Salah , ini adalah artikel yang sangat panjang, yang saya sarankan untuk membaca secara keseluruhan, tetapi jika Anda ingin melompat langsung ke kasing yang ada, cari 'TypeFromType', tetapi untuk memberi Anda TL; DR, idenya adalah yang myint = intFromStr( mystr )jauh lebih baik daripada myint = strToInt( mystr ), karena dalam kasus pertama nama-nama jenisnya dekat dengan nilai yang terkait, sehingga Anda dapat dengan mudah melihat bahwa 'int' cocok dengan 'int' dan 'str' cocok dengan 'str'.

Jadi, dengan ekstensi, saya cenderung memesan hal-hal dengan cara mereka akan muncul dalam kode.

Mike Nakis
sumber
1
Solusi ini benar-benar bagus, tampaknya bahkan lebih antipeluru dari Pemasok java sendiri, Konsumen, BiFunction, ..., karena meletakkan semuanya ke dua konsep saja. Ini mengingatkan saya pada jawaban @Karl Bielefeldt tentang " pilihan Java untuk melakukannya dengan nama yang terpisah untuk setiap arity [yang] bodoh ". Satu-satunya "downside" adalah bahwa ia tidak menangani tipe primitif dan kombinasinya (hal-hal menyenangkan seperti DoubleToLongFunction, ToLongBiFunction, ...). Tapi primitif adalah masalah lain ...
superbob
Iya. Pada dasarnya, setelah Anda mulai mengganti obat generik dengan primitif, ini berarti Anda benar-benar peduli dengan kinerja, jadi tidak apa-apa jika Anda menyimpang dari konvensi yang disajikan di sini dan menggunakan nama yang sangat disesuaikan untuk peningkatan kinerja yang sangat khusus.
Mike Nakis
1
Jika saya dapat menerima jawaban ke-2, saya akan memilih jawaban Anda berkat Prosedur N , Fungsi N saran. Saya masih memvotasikannya.
superbob
Kenapa tidak Function1<T1, R>?
ErikE
@ErikE itu pertanyaan yang sangat bagus, dan saya mengubah posting saya untuk menjawabnya.
Mike Nakis
18

Mengapa tidak Command? Mengingat bahwa itu tidak memerlukan data dan tidak mengembalikan data, tetapi dengan asumsi bahwa panggilan itu menyebabkan beberapa efek (jika tidak, itu akan benar-benar sia-sia), saya kira itu kira-kira satu-satunya hal yang dapat dilakukannya - memecat suatu tindakan, membuat sesuatu terjadi.

Omong-omong, ada juga Actiondelegasi generik di .NET. Tidak seperti Java, Consumerdapat mengambil dari 0 hingga 16 argumen; dengan kata lain, versi paling sederhana tidak diperlukan - lihat MSDN .

Dan karena namanya tidak menyiratkan ada sesuatu untuk "dikonsumsi", itu juga sepertinya pilihan nama yang bagus.

Konrad Morawski
sumber
1
Commanditu bagus. Ini dapat dikacaukan dengan pola Command tetapi mungkin itu solusinya.
superbob
7
Saya suka Actionlebih dari Command. Perintah terdengar lebih seperti sesuatu yang diterima dan dievaluasi, sementara suatu tindakan dieksekusi untuk efek sampingnya.
Bergi
7
Umm ... bagaimana bisa itu bukan pola Perintah? Anda telah membangun entitas Command persis! Bahkan memiliki execute()metode yang dinamai secara tradisional . 0_o '
hijarian
1
Tidak menyukai saran Tindakan, karena itu adalah antarmuka Ayunan yang umum (dan baik). Perintah itu masuk akal.
user949300
@ user949300 tapi itu tergantung pada konteksnya - Jawa adalah dunia yang besar, saya seorang pengembang Android (sekarang) dan saya tidak punya kekhasan terkait J2EE;) Saya setuju, tentu saja, tentu saja, konvensi penamaan yang dipilih tidak boleh berbenturan. dengan yang digunakan kerangka kerja Anda.
Konrad Morawski