Dalam salah satu ulasan kode pertama saya (beberapa waktu lalu), saya diberitahu bahwa praktik yang baik untuk memasukkan klausa default di semua pernyataan switch. Saya baru-baru ini mengingat nasihat ini tetapi tidak ingat apa itu pembenaran. Kedengarannya aneh bagi saya sekarang.
Apakah ada alasan yang masuk akal untuk selalu menyertakan pernyataan default?
Apakah bahasa ini tergantung? Saya tidak ingat bahasa apa yang saya gunakan saat itu - mungkin ini berlaku untuk beberapa bahasa dan tidak untuk yang lain?
default
switch-statement
tttppp
sumber
sumber
Jawaban:
Switch case hampir selalu memiliki
default
case.Alasan menggunakan a
default
1. Untuk 'menangkap' nilai yang tidak terduga
2. Untuk menangani tindakan 'default', di mana kasing adalah untuk perilaku khusus.
Anda melihat ini BANYAK dalam program berbasis menu dan skrip bash shell. Anda mungkin juga melihat ini ketika sebuah variabel dideklarasikan di luar switch-case tetapi tidak diinisialisasi, dan setiap case menginisialisasi ke sesuatu yang berbeda. Di sini standar perlu menginisialisasi juga sehingga kode baris yang mengakses variabel tidak menimbulkan kesalahan.
3. Untuk menunjukkan kepada seseorang yang membaca kode Anda bahwa Anda telah membahas kasus itu.
Ini adalah contoh yang terlalu disederhanakan, tetapi intinya adalah bahwa seseorang yang membaca kode seharusnya tidak bertanya-tanya mengapa
variable
tidak bisa menjadi sesuatu selain 1 atau 2.Satu-satunya kasus yang dapat saya pikirkan untuk TIDAK digunakan
default
adalah ketika saklar memeriksa sesuatu yang agak jelas setiap alternatif lain dapat dengan senang hati diabaikansumber
enum MyEnum { FOO = 0, BAR = 1 }; MyEnum value = (MyEnum)2;
membuatMyEnum
instance yang valid yang tidak sama denganFOO
atauBAR
. Jika salah satu dari masalah ini akan menyebabkan kesalahan dalam proyek Anda, kasus default akan membantu Anda menemukan kesalahan dengan sangat cepat, seringkali tanpa perlu debugger!Tidak.
Bagaimana jika tidak ada tindakan default, konteks penting. Bagaimana jika Anda hanya peduli untuk bertindak berdasarkan beberapa nilai?
Ambil contoh membaca penekanan tombol untuk gim
Menambahkan:
Hanya buang-buang waktu dan menambah kompleksitas kode tanpa alasan.
sumber
// do nothing
komentar sederhana membuat jelas bahwa itu 'ok' jika tidak semua kasus dicakup, sebagai lawan dari pernyataan switch lainnya di mana ini akan menjadi 'tidak ok'.TIDAK memiliki kasing yang sebenarnya dapat bermanfaat dalam beberapa situasi.
Jika sakelar Anda adalah nilai enum, dengan tidak memiliki kasing default, Anda bisa mendapatkan peringatan kompilator jika Anda kehilangan kasing apa pun. Dengan begitu, jika nilai enum baru ditambahkan di masa mendatang dan Anda lupa menambahkan case untuk nilai-nilai ini di sakelar, Anda bisa mencari tahu tentang masalah pada waktu kompilasi. Anda harus tetap memastikan kode mengambil tindakan yang sesuai untuk nilai yang tidak ditangani, jika nilai yang tidak valid dilemparkan ke jenis enum. Jadi ini mungkin bekerja paling baik untuk kasus-kasus sederhana di mana Anda dapat kembali dalam kasus enum daripada istirahat.
sumber
Saya akan selalu menggunakan klausa default, tidak peduli bahasa apa yang Anda gunakan.
Hal-hal dapat dan memang salah. Nilai tidak akan seperti yang Anda harapkan, dan seterusnya.
Tidak ingin memasukkan klausa default menyiratkan Anda yakin bahwa Anda tahu set nilai yang mungkin. Jika Anda yakin mengetahui set nilai yang mungkin, jika nilai berada di luar nilai yang mungkin, Anda ingin diberi tahu tentangnya - ini tentu saja merupakan kesalahan.
Itulah alasan mengapa Anda harus selalu menggunakan klausa default dan melemparkan kesalahan, misalnya di Jawa:
Tidak ada alasan untuk memasukkan lebih banyak informasi daripada hanya string yang "tidak terjangkau"; jika itu benar-benar terjadi, Anda harus melihat sumber dan nilai-nilai variabel dll, dan stacktrace pengecualian akan menyertakan nomor baris itu, jadi tidak perlu membuang waktu Anda menulis lebih banyak teks ke dalam pesan pengecualian.
sumber
throw new RuntimeException("myVar invalid " + myVar);
karena itu mungkin memberi Anda cukup info untuk mencari tahu dan memperbaiki bug tanpa harus menggunakan debugger dan memeriksa variabel, yang mungkin sulit jika ini adalah masalah yang jarang terjadi yang sulit untuk mereproduksi.default:
. Tetapi lebih sering tidak, seseorang meninggalkan default karena orang berpikirmyVar
tidak akan pernah memiliki nilai selain dari yang terdaftar; namun saya tidak dapat menghitung berapa kali saya terkejut dalam kehidupan nyata ketika variabel memiliki nilai selain dari nilai-nilai yang "mungkin" miliki. Dalam kasus tersebut, saya berterima kasih atas pengecualian yang membuat saya langsung melihatnya, daripada menyebabkan beberapa kesalahan lain di kemudian hari (lebih sulit untuk di-debug) atau jawaban yang salah (mungkin terlewatkan dalam pengujian).AssertionError
bukanRuntimeException
, karena situasi ini sangat mirip dengan pernyataan yang menyatakan bahwa itumyVar
adalah salah satu nilai yang ditangani. Juga kemungkinan seseorang menangkap dan menelan kesalahan lebih kecil.Di perusahaan saya, kami menulis perangkat lunak untuk pasar Avionik dan Pertahanan, dan kami selalu menyertakan pernyataan default, karena SEMUA kasus dalam pernyataan switch harus ditangani secara eksplisit (bahkan jika itu hanya komentar yang mengatakan 'Jangan lakukan apa-apa'). Kami tidak dapat membeli perangkat lunak hanya untuk berperilaku tidak pantas atau hanya mogok pada nilai yang tidak terduga (atau bahkan yang kami pikir tidak mungkin).
Dapat didiskusikan bahwa kasing standar tidak selalu diperlukan, tetapi dengan selalu memerlukannya, kasing mudah diperiksa oleh penganalisa kode kami.
sumber
Haruskah pernyataan "switch" selalu menyertakan klausa default? Tidak Perlu biasanya menyertakan default.
Termasuk klausa default hanya masuk akal jika ada sesuatu untuk dilakukan, seperti menyatakan kondisi kesalahan atau memberikan perilaku default. Termasuk satu "hanya karena" adalah pemrograman pemujaan kargo dan tidak memberikan nilai. Ini adalah "saklar" yang setara dengan mengatakan bahwa semua pernyataan "jika" harus menyertakan "lain".
Berikut ini adalah contoh sepele di mana itu tidak masuk akal:
Ini setara dengan:
sumber
default:
dalam kasus-kasus itu dikodifikasikan asumsi Anda. Sebagai contoh, apakah boleh ketikasgn==0
mencetakinteger
(baik positif maupun negatif), atau apakah itu kesalahan? Bagi saya membaca kode itu, sulit dikatakan. Saya berasumsi Anda tidak ingin menuliszero
dalam kasus ituinteger
, dan programmer membuat asumsi yangsgn
hanya bisa -1 atau +1. Jika itu yang terjadi, memilikidefault:
akan memungkinkan programmer untuk menangkap asumsi awal dan mengubah kode.Sejauh yang saya lihat jawabannya adalah 'default' adalah opsional, mengatakan switch harus selalu berisi default seperti mengatakan setiap 'if-elseif' harus mengandung 'lain'. Jika ada logika yang harus dilakukan secara default, maka pernyataan 'default' harus ada di sana, tetapi sebaliknya kode dapat terus dieksekusi tanpa melakukan apa pun.
sumber
Memiliki klausa default ketika itu tidak benar - benar diperlukan adalah pemrograman Defensive Ini biasanya mengarah ke kode yang terlalu kompleks karena terlalu banyak kode penanganan kesalahan. Kode penanganan dan deteksi kesalahan ini merusak keterbacaan kode, membuat pemeliharaan lebih sulit, dan akhirnya menyebabkan lebih banyak bug daripada memecahkannya.
Jadi saya percaya bahwa jika defaultnya tidak tercapai - Anda tidak perlu menambahkannya.
Perhatikan bahwa "tidak boleh dijangkau" berarti bahwa jika itu mencapai itu adalah bug dalam perangkat lunak - Anda perlu menguji nilai yang mungkin mengandung nilai yang tidak diinginkan karena input pengguna, dll.
sumber
Saya akan mengatakan itu tergantung pada bahasa, tetapi dalam C jika Anda mengaktifkan jenis enum dan Anda menangani setiap nilai yang mungkin, Anda mungkin lebih baik TIDAK termasuk case default. Dengan begitu, jika Anda menambahkan tag enum tambahan nanti dan lupa menambahkannya ke sakelar, kompiler yang kompeten akan memberi Anda peringatan tentang kasing yang hilang.
sumber
gcc -Wall
(semacam penyebut umum yang paling rendah dari kompiler yang kompeten) memberikan peringatan tentang enum yang tidak ditangani dalam pernyataan sakelar.Jika Anda tahu bahwa pernyataan switch hanya akan memiliki satu set label atau nilai yang didefinisikan dengan ketat, lakukan saja ini untuk menutupi basis, dengan cara itu Anda akan selalu mendapatkan hasil yang valid .. Masukkan saja default di atas label yang akan diprogram / secara logis menjadi penangan terbaik untuk nilai-nilai lainnya.
sumber
default
masih diperlukan di sini? Atau apakah melakukan ini memungkinkan beberapa sintaks khusus yang memungkinkan Anda menghilangkannya?Paling tidak itu tidak wajib di Jawa. Menurut JLS, katanya paling tidak satu kasus default dapat hadir. Yang berarti tidak ada case standar yang dapat diterima. Kadang-kadang juga tergantung pada konteks bahwa Anda menggunakan pernyataan switch. Misalnya di Jawa, blok sakelar berikut ini tidak memerlukan kasing standar
Tetapi dalam metode berikut yang mengharapkan untuk mengembalikan sebuah String, case default berguna untuk menghindari kesalahan kompilasi
meskipun Anda dapat menghindari kesalahan kompilasi untuk metode di atas tanpa memiliki case default dengan hanya memiliki pernyataan pengembalian di akhir, tetapi menyediakan case default membuatnya lebih mudah dibaca.
sumber
Beberapa pedoman (kedaluwarsa) mengatakan demikian, seperti MISRA C :
Saran itu sudah usang karena tidak didasarkan pada kriteria yang relevan saat ini. Kelalaian yang mencolok adalah apa yang Harlan Kassler katakan:
Meninggalkan case default memungkinkan kompiler untuk secara opsional memperingatkan atau gagal ketika melihat case yang tidak ditangani. Bagaimanapun, verifikasi statis lebih baik daripada pemeriksaan dinamis, dan karenanya bukan pengorbanan yang layak ketika Anda membutuhkan pemeriksaan dinamis juga.
Seperti yang diperlihatkan Harlan, ekuivalen fungsional dari kasing standar dapat diciptakan kembali setelah sakelar. Yang sepele ketika setiap kasus adalah pengembalian awal.
Kebutuhan khas untuk pemeriksaan dinamis adalah penanganan input, dalam arti luas. Jika nilai berasal dari luar kendali program, itu tidak bisa dipercaya.
Di sinilah Misra mengambil sudut pandang pemrograman defensif ekstrem, di mana selama nilai yang tidak valid dapat diwakili secara fisik, itu harus diperiksa, tidak peduli apakah program tersebut terbukti benar. Yang masuk akal jika perangkat lunak harus seandal mungkin dengan adanya kesalahan perangkat keras. Tapi seperti kata Ophir Yoktan, sebagian besar perangkat lunak lebih baik tidak "menangani" bug. Praktek yang terakhir ini kadang-kadang disebut pemrograman ofensif .
sumber
Anda harus memiliki default untuk menangkap nilai yang tidak diharapkan masuk.
Namun, saya tidak setuju dengan Adrian Smith bahwa pesan kesalahan Anda untuk default seharusnya menjadi sesuatu yang sama sekali tidak berarti. Mungkin ada kasus yang tidak ditangani yang tidak Anda lihat (yang merupakan pokok permasalahan) yang pada akhirnya akan dilihat oleh pengguna Anda dan pesan seperti "tidak dapat dijangkau" sama sekali tidak ada gunanya dan tidak membantu siapa pun dalam situasi itu.
Contohnya, berapa kali Anda mengalami BSOD yang sama sekali tidak berarti? Atau pengecualian fatal @ 0x352FBB3C32342?
sumber
Jika nilai sakelar ( sakelar (variabel )) tidak dapat mencapai kasing standar, maka kasing standar sama sekali tidak diperlukan. Bahkan jika kita menyimpan case default, itu sama sekali tidak dieksekusi. Itu kode mati.
sumber
Ini adalah 'konvensi' pengkodean opsional. Tergantung pada penggunaannya apakah diperlukan atau tidak. Saya pribadi percaya bahwa jika Anda tidak membutuhkannya tidak seharusnya ada di sana. Mengapa menyertakan sesuatu yang tidak akan digunakan atau dijangkau oleh pengguna?
Jika kemungkinan case terbatas (yaitu Boolean) maka klausa default adalah redundan !
sumber
Jika tidak ada kasus default dalam
switch
pernyataan, perilaku bisa tidak dapat diprediksi jika kasus itu muncul di beberapa titik waktu, yang tidak dapat diprediksi pada tahap pengembangan. Ini adalah praktik yang baik untuk memasukkandefault
kasus.Praktek semacam itu dapat menghasilkan bug seperti dereference NULL , kebocoran memori serta jenis bug serius lainnya .
Sebagai contoh, kami berasumsi bahwa setiap kondisi menginisialisasi pointer. Tetapi jika
default
case seharusnya muncul dan jika kita tidak menginisialisasi dalam kasus ini, maka ada setiap kemungkinan mendarat dengan pengecualian null pointer. Oleh karena itu disarankan untuk menggunakandefault
pernyataan kasus, meskipun itu mungkin sepele.sumber
Kasing standar mungkin tidak diperlukan dalam sakelar yang digunakan oleh enum. ketika switch berisi semua nilai, case default tidak akan pernah dijalankan. Jadi dalam hal ini, itu tidak perlu.
sumber
Bergantung pada bagaimana switch dalam bahasa tertentu bekerja, namun dalam kebanyakan bahasa ketika tidak ada kasus yang cocok, eksekusi jatuh melalui pernyataan switch tanpa peringatan. Bayangkan Anda mengharapkan beberapa set nilai dan menanganinya secara bergantian, namun Anda mendapatkan nilai lain dalam input. Tidak ada yang terjadi dan Anda tidak tahu tidak ada yang terjadi. Jika Anda menangkap case secara default, Anda akan tahu ada sesuatu yang salah.
sumber
Saya tidak setuju dengan jawaban Vanwaril yang paling banyak dipilih di atas.
Kode apa pun menambah kompleksitas. Juga tes dan dokumentasi harus dilakukan untuk itu. Jadi selalu baik jika Anda dapat memprogram menggunakan lebih sedikit kode. Pendapat saya adalah bahwa saya menggunakan klausa default untuk pernyataan switch tidak lengkap sementara saya tidak menggunakan klausa default untuk pernyataan switch lengkap. Untuk memastikan bahwa saya melakukannya dengan benar, saya menggunakan alat analisis kode statis. Jadi mari kita masuk ke detail:
Tidak ada pernyataan beralih yang lengkap: Itu harus selalu memiliki nilai default. Seperti namanya itu adalah pernyataan yang tidak mencakup semua nilai yang mungkin. Ini juga mungkin tidak mungkin, misalnya pernyataan switch pada nilai integer atau pada String. Di sini saya ingin menggunakan contoh Vanwaril (Harus disebutkan bahwa saya pikir dia menggunakan contoh ini untuk membuat saran yang salah. Saya menggunakannya di sini untuk menyatakan sebaliknya -> Gunakan pernyataan default):
Pemain dapat menekan tombol lainnya. Maka kita tidak bisa melakukan apa-apa (ini dapat ditunjukkan dalam kode hanya dengan menambahkan komentar ke case default) atau seharusnya misalnya mencetak sesuatu di layar. Kasus ini relevan karena mungkin terjadi.
Pernyataan sakelar yang lengkap: Pernyataan sakelar tersebut mencakup semua nilai yang mungkin, misalnya, pernyataan sakelar pada enumerasi tipe sistem kelas. Saat mengembangkan kode pertama kali mudah untuk mencakup semua nilai. Namun, karena kita adalah manusia, ada sedikit peluang untuk melupakan sebagian. Selain itu jika Anda menambahkan nilai enum nanti sehingga semua pernyataan beralih harus disesuaikan untuk membuatnya lengkap lagi membuka jalan ke kesalahan neraka. Solusi sederhana adalah alat analisis kode statis. Alat ini harus memeriksa semua pernyataan sakelar dan memeriksa apakah mereka lengkap atau apakah mereka memiliki nilai default. Berikut ini contoh pernyataan peralihan lengkap. Pertama kita membutuhkan enum:
Maka kita perlu variabel seperti enum ini
GradeSystemType type = ...
. Pernyataan sakelar yang lengkap akan terlihat seperti ini:Jadi, jika kita memperpanjang
GradeSystemType
dengan misalnyaSystem1To3
alat analisis kode statis harus mendeteksi bahwa tidak ada klausa default dan pernyataan beralih tidak lengkap sehingga kami menyimpan.Hanya satu hal tambahan. Jika kita selalu menggunakan
default
klausa, mungkin terjadi bahwa alat analisis kode statis tidak mampu mendeteksi pernyataan beralih lengkap atau tidak lengkap karena selalu mendeteksidefault
klausa. Ini sangat buruk karena kami tidak akan diberi tahu jika kami memperpanjang enum dengan nilai lain dan lupa menambahkannya ke satu pernyataan switch.sumber
Haruskah beralih pernyataan selalu mengandung klausa default? Tidak ada kasus sakelar yang ada tanpa kasing standar, dalam kasing standar kasing akan memicu nilai sakelar
switch(x)
dalam kasing x ini ketika tidak cocok dengan nilai kasing lainnya.sumber
Saya percaya ini cukup spesifik bahasa dan untuk kasus C ++ titik kecil untuk tipe kelas enum . Yang tampak lebih aman daripada C enum tradisional. TAPI
Jika Anda melihat implementasi std :: byte-nya sesuatu seperti:
Sumber: https://en.cppreference.com/w/cpp/language/enum
Dan pertimbangkan juga ini:
Sumber: https://en.cppreference.com/w/cpp/language/list_initialization
Ini adalah contoh kelas enum yang mewakili nilai-nilai yang tidak didefinisikan enumerator. Karena alasan ini, Anda tidak dapat menaruh kepercayaan penuh pada enum. Tergantung pada aplikasi ini mungkin penting.
Namun, saya sangat suka apa yang dikatakan @Harlan Kassler di posnya dan akan mulai menggunakan strategi itu dalam beberapa situasi sendiri.
Contoh kelas enum yang tidak aman:
sumber