Mengapa 'void' tidak diizinkan sebagai tipe umum di C #

53

Apa keputusan desain yang mendukung voidtidak dapat dibangun dan tidak diizinkan sebagai tipe generik? Bagaimanapun, ini hanyalah kekosongan khusus structdan akan menghindari total PITA untuk memiliki yang berbeda Funcdan Actiondelegasi.

(C ++ memungkinkan voidpengembalian eksplisit dan memungkinkan voidsebagai parameter templat)

Thomas Owens
sumber
13
@Oded Menimbang bahwa Eric Lippert memiliki akun dan berpartisipasi di Programmer , saya pikir dia baru saja melakukannya.
Thomas Owens
2
@ BenVoigt Tidak perlu membutuhkan pengetahuan satu orang, meskipun ada satu orang di sini yang dapat (dengan mudah, saya asumsikan) memberikan jawaban yang benar. Siapa pun yang mengenal spesifikasi mungkin dapat menjawab pertanyaan, terutama jika mereka memiliki pengetahuan tentang desain bahasa pemrograman. Ini juga pertanyaan desain / implementasi bahasa yang menarik, yang merupakan topik di sini.
Thomas Owens
6
@BenVoigt: Mengapa Anda begitu ingin memiliki pertanyaan yang benar-benar valid dan menarik ditutup tanpa alasan yang baik, selain untuk memuaskan kericuhan Anda sendiri? Saya telah mencari dan tidak dapat menemukan jawabannya; mungkin seseorang di sini telah membaca posting blog tentang hal itu, mungkin orang-orang yang mengambil keputusan ingin menjawab pertanyaan, mungkin seseorang mendapat obrolan kepada orang-orang yang membuat keputusan tentang hal ini dan mengajukan pertanyaan sendiri dan dapat meneruskan jawabannya. Saya sudah berhenti memposting di situs ini dan BEGITU cukup banyak karena orang-orang tampaknya jauh lebih tertarik untuk menutup pertanyaan daripada menjawab pertanyaan.
4
Saya bisa menunjukkan "titik besar" pertanyaan dan jawaban di sini dan terutama pada SO umumnya dari bentuk "apa arti sintaksis ini?" Pertanyaan-pertanyaan itu hampir tidak pernah ditutup karena semua orang bisa menumpuk dan mengeluarkan definisi untuk const pointers ke const object. Pertanyaan-pertanyaan yang lebih menarik yang terletak di luar jalur terpencil dapat diburu keluar dari situs karena beberapa alasan: serius, itu hanya beberapa kilobyte di gudang data di suatu tempat. Bisakah kita semua santai dan merangkul belajar daripada memaksakan aturan yang ditafsirkan sewenang-wenang yang melayani tujuan yang sangat sedikit?
2
@ThomasOwens: Saya dalam arti lebih aktif di situs ini daripada di SO. Di situs ini saya mengirim jawaban untuk sekitar satu pertanyaan di setiap 300. Pada SO saya mengirim jawaban untuk sekitar satu pertanyaan di setiap 1500. Perbedaan dalam aktivitas jumlah jawaban semata-mata disebabkan oleh jumlah peluang yang jauh lebih tinggi untuk menjawab pertanyaan C # di SO.
Eric Lippert

Jawaban:

69

Masalah mendasar dengan "void" adalah bahwa itu tidak berarti hal yang sama dengan tipe pengembalian lainnya. "void" berarti "jika metode ini kembali maka tidak ada nilai sama sekali." Bukan nol; null adalah sebuah nilai. Sama sekali tidak mengembalikan nilai.

Ini benar-benar mengacaukan sistem tipe. Sistem tipe pada dasarnya adalah sistem untuk membuat deduksi logis tentang operasi apa yang valid pada nilai-nilai tertentu; metode pengembalian batal tidak mengembalikan nilai, jadi pertanyaan "operasi apa yang valid untuk hal ini?" sama sekali tidak masuk akal. Tidak ada "hal" untuk dioperasi, valid atau tidak valid.

Selain itu, ini mengacaukan sesuatu runtime sengit. .NET runtime adalah implementasi dari Sistem Eksekusi Virtual, yang ditentukan sebagai mesin stack. Yaitu, mesin virtual di mana operasi semua ditandai dalam hal efeknya pada tumpukan evaluasi. (Tentu saja dalam praktiknya mesin akan diimplementasikan pada mesin dengan tumpukan dan register, tetapi sistem eksekusi virtual mengasumsikan hanya tumpukan.) Efek panggilan ke metode batal pada dasarnyaberbeda dari efek panggilan ke metode non-void; metode non-void selalu menempatkan sesuatu pada stack, yang mungkin perlu dihapus. Metode batal tidak pernah menempatkan sesuatu di tumpukan. Dan karenanya kompiler tidak dapat memperlakukan metode void dan non-void sama dalam kasus di mana nilai yang dikembalikan metode diabaikan; jika metode ini batal maka tidak ada nilai balik sehingga tidak boleh ada pop.

Untuk semua alasan ini, "void" bukan tipe yang bisa dipakai; tidak memiliki nilai , itulah intinya. Ini tidak dapat dikonversi ke objek, dan metode pengembalian batal tidak pernah dapat diperlakukan secara polimorfik dengan metode non-batal-kembali karena melakukan hal itu merusak tumpukan!

Dengan demikian, void tidak dapat digunakan sebagai argumen tipe, yang memalukan, seperti yang Anda catat. Akan sangat nyaman.

Dengan manfaat melihat ke belakang, akan lebih baik bagi semua pihak yang peduli jika alih-alih tidak melakukan apa pun, metode pengembalian yang kosong secara otomatis mengembalikan "Unit", tipe referensi tunggal ajaib. Anda kemudian akan tahu bahwa setiap pemanggilan metode meletakkan sesuatu di tumpukan , Anda akan tahu bahwa setiap pemanggilan metode mengembalikan sesuatu yang dapat ditugaskan ke variabel tipe objek , dan tentu saja Unit dapat digunakan sebagai argumen tipe , sehingga akan ada tidak perlu memiliki tipe delegasi Aksi dan Fungsi yang terpisah. Sayangnya, itu bukan dunia tempat kita berada.

Untuk beberapa pemikiran lain dalam nada ini, lihat:

Eric Lippert
sumber
C ++ mendukungnya tanpa harus menggunakan tipe singleton magis. Tapi saya berasumsi itu ada hubungannya dengan C ++ menggunakan gaya "generik" yang sama sekali berbeda dari C #.
Winston Ewert
4
@ WinstonEwert - Saya cukup yakin C ++ tidak mendukung obat generik sama sekali, melainkan memiliki template, yang pada dasarnya berbeda. Seperti yang saya pahami, dengan template kompiler melakukan pencarian global dan ganti dengan parameter tipe Anda, tetapi dengan generik, sistem tipe menciptakan tipe yang tepat. Saya juga berpikir itu sebabnya kesalahan template C ++ begitu tumpul. Saya yakin Eric akan memperbaiki saya jika saya mengatakan sesuatu yang tidak beres
Adam Rackis
1
Saya pikir semua struct ditangani pada waktu kompilasi untuk mendapatkan penempatan yang tepat pada stack dan di tempat lain di mana mereka digariskan. Dengan demikian Voidharus ok untuk diteruskan sebagai jumlah tak terbatas argumen di dalam 0 stack byte. Ketika struktur apa pun perlu dikonversikan ke objectatau memanggil metode (untuk mendapatkan this) itu kotak dengan menempatkan pada tumpukan dengan Typereferensi dimasukkan sebelum bidang bidang memori (untuk banyak implementasi CLR) dan dengan demikian dapat ditangani dengan benar. Adapun tipe saya hanyalah pengelompokan objek yang dapat dibedakan berdasarkan beberapa karakteristik (bidang). Voidhanyalah satu objek.
ony
1
@ OlivierJacot-Descombes: Jika voidadalah tipe nilai kosong, maka pernyataan itu akan diterjemahkan menjadi nol instruksi kode mesin. Tidak terlalu berguna untuk tipe hard-coded Void, tetapi berguna dalam kasus-kasus di mana tipe memiliki beberapa parameter umum tetapi beberapa tidak diperlukan dalam kasus-kasus tertentu.
supercat
2
@ EricLippert: Penanganan yang tepat dari nilai-nilai tipe pengembalian akan membutuhkan kemampuan untuk memunculkan sejumlah kata dari tumpukan. Apakah akan ada kesulitan mendasar dengan membiarkan jumlah kata menjadi nol? Jika penelepon bertanggung jawab untuk mengalokasikan ruang dan melewati byref, sistem tipe harus mengenali bahwa void byref tidak memiliki arti, dan mungkin itu tidak dianggap sepadan dengan usaha, tapi saya tidak melihat masalah "mendasar" .
supercat
9

Dari: http://connect.microsoft.com/VisualStudio/feedback/details/94226/allow-void-to-be-parameter-of-generic-class-if-not-in-c-then-just-in- runtime

Ini sebenarnya berdasarkan desain - kami tidak mengizinkan instance jenis void (bersama dengan banyak tipe lain dalam runtime). Anda tidak bisa membuat void atau void [] baik. Kami memasang lubang jenis ini untuk keamanan.

Saya tidak bisa seumur hidup saya melihat bagaimana kekosongan adalah lubang keamanan, tapi ... begitulah katanya.

Winston Ewert
sumber