Mengapa casting harus dihindari? [Tutup]

97

Saya biasanya menghindari tipe casting sebanyak mungkin karena saya mendapat kesan bahwa itu adalah praktik pengkodean yang buruk dan mungkin menimbulkan penalti kinerja.

Tetapi jika seseorang meminta saya untuk menjelaskan mengapa tepatnya itu terjadi, saya mungkin akan melihat mereka seperti rusa di lampu depan.

Jadi mengapa / kapan casting itu buruk?

Apakah umum untuk java, c #, c ++ atau apakah setiap lingkungan runtime yang berbeda menghadapinya dengan persyaratannya sendiri?

Spesifik untuk bahasa apapun diperbolehkan, contoh mengapa buruk di c ++?

KerasNMungkin Salah
sumber
3
Dari mana Anda mendapatkan kesan ini?
Oded
8
Saya mendapat kesan ini karena saya tidak pernah membaca buku atau bertemu dengan programmer yang mengatakan "CASTING SOOOO GOOOOD !!!"
LoudNPossiblyWrong
15
Jawaban C ++ pasti berbeda dengan jawaban C #. Ini sangat spesifik bahasa. Jawaban sejauh ini menjawab pertanyaan ini untuk bahasa tertentu dan dalam beberapa kasus tidak menyatakan bahasa apa yang mereka bicarakan.
James McNellis
2
Buruk adalah istilah yang relatif. Menghindari casting adalah praktik terbaik, tetapi terkadang programmer harus melakukan apa yang harus dilakukan oleh programmer. (terutama jika Anda menulis program java 1.5+ yang menggunakan pustaka yang ditulis untuk 1.4) Mungkin mengganti nama pertanyaan, "Mengapa casting harus dihindari?"
Mike Miller
2
Ini adalah pertanyaan yang bagus .... Ditutup oleh 5 pengguna yang masing-masing memiliki reputasi kurang dari 10k !! Penggunaan kekuatan baru yang berlebihan, jelas. Telah memilih untuk membuka kembali.
reach4thelasers

Jawaban:

141

Anda telah menandai ini dengan tiga bahasa, dan jawabannya sangat berbeda di antara ketiganya. Diskusi tentang C ++ kurang lebih menyiratkan diskusi tentang pemeran C juga, dan itu memberikan (lebih atau kurang) jawaban keempat.

Karena itu yang tidak Anda sebutkan secara eksplisit, saya akan mulai dengan C. Pemain C memiliki sejumlah masalah. Pertama, mereka dapat melakukan salah satu dari sejumlah hal yang berbeda. Dalam beberapa kasus, cast tidak lebih dari memberitahu compiler (pada intinya): "diam, saya tahu apa yang saya lakukan" - yaitu, memastikan bahwa bahkan ketika Anda melakukan konversi yang dapat menyebabkan masalah, compiler tidak akan memperingatkan Anda tentang potensi masalah tersebut. Misalnya saja char a=(char)123456;,. Hasil pasti dari implementasi ini ditentukan (tergantung pada ukuran dan penandatangananchar), dan kecuali dalam situasi yang agak aneh, mungkin tidak berguna. Cast C juga bervariasi apakah itu sesuatu yang terjadi hanya pada waktu kompilasi (yaitu, Anda hanya memberi tahu kompiler cara menafsirkan / memperlakukan beberapa data) atau sesuatu yang terjadi pada waktu proses (misalnya, konversi aktual dari ganda menjadi panjang).

C ++ mencoba untuk menangani hal itu setidaknya sampai batas tertentu dengan menambahkan sejumlah operator cast "baru", yang masing-masing dibatasi hanya untuk sebagian dari kemampuan cast C. Hal ini membuat lebih sulit untuk (misalnya) secara tidak sengaja melakukan konversi yang sebenarnya tidak Anda inginkan - jika Anda hanya bermaksud membuang kekonstanan pada suatu objek, Anda dapat menggunakan const_cast, dan memastikan bahwa satu - satunya hal yang dapat dipengaruhi adalah apakah sebuah benda const, volatileatau tidak. Sebaliknya, a static_casttidak diperbolehkan untuk mempengaruhi apakah suatu objek adalah constatauvolatile. Singkatnya, Anda memiliki sebagian besar jenis kemampuan yang sama, tetapi kemampuan tersebut dikategorikan sehingga satu pemeran biasanya hanya dapat melakukan satu jenis konversi, di mana satu pemeran gaya C dapat melakukan dua atau tiga konversi dalam satu operasi. Pengecualian utamanya adalah Anda dapat menggunakan a dynamic_castsebagai pengganti a static_castsetidaknya dalam beberapa kasus dan meskipun ditulis sebagai a dynamic_cast, itu akan benar-benar berakhir sebagai a static_cast. Misalnya, Anda dapat menggunakan dynamic_castuntuk melintasi ke atas atau ke bawah hierarki kelas - tetapi cast "ke atas" hierarki selalu aman, sehingga dapat dilakukan secara statis, sementara cast "ke bawah" hierarki tidak selalu aman sehingga dilakukan secara dinamis.

Java dan C # jauh lebih mirip satu sama lain. Secara khusus, dengan keduanya, casting selalu merupakan operasi run-time. Dalam hal operator cast C ++, biasanya ini paling dekat dengan a dynamic_castdalam hal apa yang sebenarnya dilakukan - yaitu, ketika Anda mencoba mentransmisikan objek ke beberapa jenis target, kompilator memasukkan pemeriksaan waktu proses untuk melihat apakah konversi itu diizinkan , dan berikan pengecualian jika tidak. Detail pastinya (misalnya, nama yang digunakan untuk pengecualian "cast buruk") bervariasi, tetapi prinsip dasarnya sebagian besar tetap serupa (meskipun, jika memori berfungsi, Java membuat cast diterapkan ke beberapa jenis non-objek seperti yang intlebih mirip dengan C gips - tetapi jenis ini cukup jarang digunakan sehingga 1) Saya tidak ingat pasti, dan 2) bahkan jika itu benar, itu tidak terlalu penting).

Melihat hal-hal secara lebih umum, situasinya cukup sederhana (setidaknya IMO): pemeran (cukup jelas) berarti Anda mengubah sesuatu dari satu jenis ke jenis lainnya. Kapan / jika Anda melakukan itu, itu menimbulkan pertanyaan "Mengapa?" Jika Anda benar-benar ingin sesuatu menjadi tipe tertentu, mengapa Anda tidak mendefinisikannya sebagai tipe itu? Itu tidak berarti tidak pernah ada alasan untuk melakukan konversi seperti itu, tetapi kapan pun itu terjadi, itu akan memunculkan pertanyaan apakah Anda dapat mendesain ulang kode sehingga tipe yang benar digunakan seluruhnya. Bahkan konversi yang tampaknya tidak berbahaya (misalnya, antara integer dan floating point) harus diperiksa lebih dekat daripada yang umum. Meskipun mereka terlihatkesamaan, bilangan bulat harus benar-benar digunakan untuk jenis hal yang "dihitung" dan titik mengambang untuk jenis hal yang "diukur". Mengabaikan perbedaan inilah yang menyebabkan beberapa pernyataan gila seperti "rata-rata keluarga Amerika memiliki 1,8 anak." Meskipun kita semua bisa melihat bagaimana itu terjadi, faktanya tidak ada keluarga yang memiliki 1,8 anak. Mereka mungkin memiliki 1 atau mungkin 2 atau mereka mungkin memiliki lebih dari itu - tetapi tidak pernah 1,8.

Jerry Coffin
sumber
10
Sepertinya Anda menderita 'kematian karena rentang perhatian' di sini, ini adalah jawaban yang bagus imo.
Steve Townsend
2
Jawaban yang kuat, tetapi beberapa bagian "Saya tidak tahu" bisa diperketat untuk membuatnya komprehensif. @ Dragontamer5788 ini adalah jawaban yang bagus, tetapi tidak komprehensif.
M2tM
5
Satu anak utuh dan satu anak dengan kaki yang hilang akan menjadi 1,8 anak. Tapi jawaban yang sangat bagus tidak kurang. :)
Oz.
1
Jawaban yang sangat bagus tidak terhambat sedikit pun dengan mengecualikan pasangan tanpa anak.
@Roger: tidak mengecualikan, hanya mengabaikan.
Jerry Coffin
48

Banyak jawaban bagus di sini. Inilah cara saya melihatnya (dari perspektif C #).

Casting biasanya berarti salah satu dari dua hal:

  • Saya tahu jenis runtime dari ekspresi ini tetapi kompiler tidak mengetahuinya. Compiler, saya beritahu Anda, pada waktu proses objek yang sesuai dengan ekspresi ini benar-benar akan menjadi tipe ini. Sampai sekarang, Anda tahu bahwa ungkapan ini harus diperlakukan sebagai tipe ini. Hasilkan kode yang mengasumsikan bahwa objek akan menjadi tipe yang diberikan, atau, berikan pengecualian jika saya salah.

  • Baik compiler maupun developer mengetahui tipe runtime dari ekspresi tersebut. Ada nilai lain dari jenis berbeda yang terkait dengan nilai yang akan dimiliki ekspresi ini pada waktu proses. Hasilkan kode yang menghasilkan nilai tipe yang diinginkan dari nilai tipe yang diberikan; jika Anda tidak dapat melakukannya, maka berikan pengecualian.

Perhatikan bahwa keduanya berlawanan . Ada dua jenis pemeran! Ada cast di mana Anda memberikan petunjuk kepada compiler tentang realitas - hei, objek bertipe ini sebenarnya bertipe Customer - dan ada cast di mana Anda memberi tahu compiler untuk melakukan pemetaan dari satu jenis ke jenis lainnya - hei, Saya membutuhkan int yang sesuai dengan double ini.

Kedua jenis pemeran itu adalah bendera merah. Jenis pemeran pertama menimbulkan pertanyaan "mengapa sebenarnya pengembang mengetahui sesuatu yang tidak diketahui oleh kompilator?" Jika Anda berada dalam situasi itu maka hal yang lebih baik untuk dilakukan biasanya mengubah program sehingga compiler benar -benar dapat menangani kenyataan. Maka Anda tidak membutuhkan pemeran; analisis dilakukan pada waktu kompilasi.

Jenis pemeran kedua menimbulkan pertanyaan "mengapa operasi tidak dilakukan pada tipe data target sejak awal?" Jika Anda membutuhkan hasil dalam int, lalu mengapa Anda memegang ganda di tempat pertama? Bukankah seharusnya Anda memegang int?

Beberapa pemikiran tambahan di sini:

http://blogs.msdn.com/b/ericlippert/archive/tags/cast+operator/

Eric Lippert
sumber
2
Saya tidak berpikir itu adalah bendera merah inheren. Jika Anda memiliki Fooobjek yang diwarisi dari Bar, dan Anda menyimpannya di a List<Bar>, maka Anda akan membutuhkan gips jika Anda menginginkannya Fookembali. Mungkin ini menunjukkan masalah pada tingkat arsitektural (mengapa kita menyimpan Bars, bukan Foos?), Tetapi tidak harus. Dan, jika itu Foojuga memiliki pemeran yang valid int, itu juga berkaitan dengan komentar Anda yang lain: Anda menyimpan Foo, bukan int, karena inttidak selalu sesuai.
Mike Caron
6
@ Mike Caron - Saya tidak bisa menjawab untuk Eric, jelas, tetapi bagi saya bendera merah berarti "ini adalah sesuatu untuk dipikirkan", bukan "ini adalah sesuatu yang salah". Dan tidak ada kesulitan menyimpan Foodalam List<Bar>, tapi pada titik pemain Anda mencoba untuk melakukan sesuatu dengan Fooyang tidak sesuai untuk Bar. Itu berarti bahwa perilaku yang berbeda untuk subtipe dilakukan melalui mekanisme selain dari polimorfisme bawaan yang disediakan oleh metode virtual. Mungkin itu solusi yang tepat, tetapi lebih sering itu adalah tanda bahaya.
Jeffrey L Memutihkan
14
Memang. Jika Anda mengeluarkan sesuatu dari daftar hewan dan kemudian Anda perlu memberi tahu penyusunnya, oh, omong-omong, saya kebetulan tahu bahwa yang pertama adalah harimau, yang kedua adalah singa, dan yang ketiga adalah seekor beruang, maka Anda seharusnya menggunakan Tuple <Lion, Tiger, Bear>, bukan List <Animal>.
Eric Lippert
5
Saya setuju dengan Anda, tetapi saya pikir tanpa dukungan sintaksis yang lebih baik untuk Tuple<X,Y,...>tuple tidak mungkin melihat penggunaan luas di C #. Ini adalah satu tempat di mana bahasa bisa melakukan pekerjaan yang lebih baik dalam mendorong orang menuju "lubang kesuksesan".
kvb
4
@kvb: Saya setuju. Kami mempertimbangkan untuk mengadopsi sintaks tupel untuk C # 4 tetapi tidak sesuai dengan anggaran. Mungkin di C # 5; kami belum mengerjakan set fitur lengkapnya. Terlalu sibuk mengumpulkan CTP untuk asinkron. Atau mungkin dalam versi hipotetis masa depan.
Eric Lippert
36

Kesalahan transmisi selalu dilaporkan sebagai kesalahan waktu proses di java. Menggunakan generik atau templat mengubah kesalahan ini menjadi kesalahan waktu kompilasi, membuatnya lebih mudah untuk mendeteksi ketika Anda membuat kesalahan.

Seperti yang saya katakan di atas. Ini bukan untuk mengatakan bahwa semua casting itu buruk. Tetapi jika mungkin untuk menghindarinya, yang terbaik adalah melakukannya.

Mike Miller
sumber
4
Ini mengasumsikan bahwa semua casting itu "buruk"; Namun, ini tidak sepenuhnya benar. Ambil C #, misalnya, dengan dukungan cast implisit dan eksplisit. Masalahnya muncul saat cast dilakukan yang (secara tidak sengaja) menghilangkan informasi atau keamanan tipe (ini berbeda menurut bahasa).
5
Sebenarnya, ini salah besar di C ++. Mungkin ada pengeditan untuk memasukkan bahasa yang ditargetkan dengan informasi ini.
Steve Townsend
@Erick - Ya, tapi saya tidak tahu apa-apa tentang Java, juga tidak cukup detail C # untuk memastikan infonya benar.
Steve Townsend
Maaf, saya orang Java, jadi pengetahuan c ++ saya cukup terbatas. Saya dapat mengedit kata "templating" darinya, karena kata itu dimaksudkan untuk menjadi tidak jelas.
Mike Miller
Tidak begitu. Beberapa kesalahan cor ditangkap oleh kompilator Java, dan bukan hanya kesalahan umum. Pertimbangkan (String) 0;
Marquis dari Lorne
18

Casting pada dasarnya tidak buruk, hanya saja sering disalahgunakan sebagai sarana untuk mencapai sesuatu yang sebenarnya tidak boleh dilakukan sama sekali, atau dilakukan dengan lebih elegan.

Jika secara universal buruk, bahasa tidak akan mendukungnya. Seperti fitur bahasa lainnya, ia memiliki tempatnya.

Saran saya adalah fokus pada bahasa utama Anda, dan memahami semua pemerannya, dan praktik terbaik terkait. Itu harus menginformasikan kunjungan ke bahasa lain.

Dokumen C # yang relevan ada di sini .

Ada ringkasan bagus tentang opsi C ++ pada pertanyaan SO sebelumnya di sini .

Steve Townsend
sumber
9

Saya kebanyakan berbicara untuk C ++ di sini, tetapi sebagian besar mungkin berlaku untuk Java dan C # juga:

C ++ adalah bahasa yang diketik secara statis . Ada beberapa kelonggaran bahasa memungkinkan Anda dalam hal ini (fungsi virtual, konversi implisit), tetapi pada dasarnya kompiler mengetahui tipe setiap objek pada waktu kompilasi. Alasan menggunakan bahasa seperti itu adalah karena kesalahan dapat diketahui pada waktu kompilasi . Jika kompilator mengetahui tipe adan b, maka ia akan menangkap Anda pada waktu kompilasi ketika Anda melakukan a=bwhere aadalah bilangan kompleks dan bmerupakan string.

Setiap kali Anda melakukan casting eksplisit, Anda memberi tahu kompiler untuk diam, karena Anda pikir Anda lebih tahu . Jika Anda salah, Anda biasanya hanya akan mengetahuinya pada saat run-time . Dan masalah dengan mencari tahu pada saat run-time adalah, bahwa ini mungkin terjadi pada pelanggan.

sbi
sumber
5

Java, c # dan c ++ adalah bahasa yang diketik dengan kuat, meskipun bahasa yang diketik dengan kuat dapat dianggap tidak fleksibel, mereka memiliki keuntungan melakukan pemeriksaan jenis pada waktu kompilasi dan melindungi Anda dari kesalahan waktu proses yang disebabkan oleh jenis yang salah untuk operasi tertentu.

Pada dasarnya ada dua jenis gips: gips ke tipe yang lebih umum atau gips ke tipe lain (lebih spesifik). Mentransmisikan ke tipe yang lebih umum (mentransmisikan ke tipe induk) akan membuat pemeriksaan waktu kompilasi tetap utuh. Tetapi mentransmisikan ke jenis lain (jenis yang lebih spesifik) akan menonaktifkan pemeriksaan jenis waktu kompilasi dan akan diganti oleh kompiler dengan pemeriksaan runtime. Ini berarti Anda kurang yakin bahwa kode yang Anda kompilasi akan berjalan dengan benar. Ini juga memiliki beberapa dampak performa yang dapat diabaikan, karena pemeriksaan jenis runtime tambahan (Java API penuh dengan cast!).

Kdeveloper
sumber
5
Tidak semua cast "bypass" type safety di C ++.
James McNellis
4
Tidak semua cast "bypass" type safety di C #.
5
Tidak semua cast "bypass" type safety di Java.
Erick Robertson
11
Tidak semua tipe cast "memotong" keamanan dalam Casting. Oh, tunggu, tag itu tidak mengacu pada bahasa ...
sbi
2
Di hampir semua kasus di C # dan Java, casting akan memberikan Anda penurunan kinerja, karena sistem akan melakukan pemeriksaan jenis run-time (yang tidak gratis). Di C ++, dynamic_castumumnya lebih lambat daripada static_cast, karena umumnya harus melakukan pengecekan tipe run-time (dengan beberapa peringatan: casting ke tipe dasar murah, dll).
Travis Gockel
4

Beberapa jenis pengecoran sangat aman dan efisien sehingga seringkali tidak dianggap sebagai pengecoran sama sekali.

Jika Anda mentransmisikan dari tipe turunan ke tipe dasar, ini biasanya cukup murah (seringkali - bergantung pada bahasa, implementasi, dan faktor lainnya - ini berbiaya nol) dan aman.

Jika Anda mentransmisikan dari tipe yang sederhana seperti int ke tipe yang lebih luas seperti int panjang, maka sekali lagi ini sering kali cukup murah (umumnya tidak jauh lebih mahal daripada menetapkan tipe yang sama seperti cor itu) dan sekali lagi aman.

Jenis lainnya lebih penuh dan / atau lebih mahal. Dalam sebagian besar bahasa, casting dari tipe dasar ke tipe turunan bisa murah tetapi memiliki risiko kesalahan parah yang tinggi (di C ++ jika Anda static_cast dari basis ke turunan itu akan murah, tetapi jika nilai yang mendasarinya bukan dari tipe turunan, perilaku tidak terdefinisi dan bisa sangat aneh) atau relatif mahal dan dengan risiko memunculkan pengecualian (dynamic_cast di C ++, cast dasar-ke-turunan eksplisit di C #, dan seterusnya). Tinju di Java dan C # adalah contoh lain dari ini, dan biaya yang lebih besar (mengingat bahwa mereka berubah lebih dari sekedar bagaimana nilai-nilai yang mendasarinya diperlakukan).

Jenis pemeran lainnya dapat kehilangan informasi (jenis bilangan bulat panjang ke jenis bilangan bulat pendek).

Kasus-kasus risiko ini (baik pengecualian atau kesalahan yang lebih serius) dan biaya adalah alasan untuk menghindari casting.

Alasan yang lebih konseptual, tetapi mungkin lebih penting, adalah bahwa setiap kasus casting adalah kasus di mana kemampuan Anda untuk bernalar tentang kebenaran kode Anda terhalang: Setiap kasus adalah tempat lain di mana sesuatu bisa salah, dan cara-cara di mana itu bisa salah menambah kompleksitas menyimpulkan apakah sistem secara keseluruhan akan salah. Bahkan jika para pemeran terbukti aman setiap saat, membuktikan ini adalah bagian tambahan dari alasannya.

Akhirnya, penggunaan gips yang berat dapat menunjukkan kegagalan untuk mempertimbangkan model objek dengan baik baik dalam membuatnya, menggunakannya, atau keduanya: Casting bolak-balik antara beberapa jenis yang sama sering hampir selalu merupakan kegagalan untuk mempertimbangkan hubungan antar jenis bekas. Di sini tidak terlalu banyak pemeran itu buruk, karena itu adalah pertanda sesuatu yang buruk.

Jon Hanna
sumber
2

Ada kecenderungan yang berkembang bagi pemrogram untuk berpegang teguh pada aturan dogmatis tentang penggunaan fitur bahasa ("jangan pernah gunakan XXX!", "XXX dianggap berbahaya", dll), di mana XXX berkisar dari gotos, pointer, protectedanggota data, lajang, hingga melewati objek nilai.

Mengikuti aturan seperti itu, menurut pengalaman saya, memastikan dua hal: Anda tidak akan menjadi programmer yang buruk, Anda juga tidak akan menjadi programmer yang hebat.

Sebuah banyak pendekatan yang lebih baik adalah untuk menggali dan mengungkap kernel kebenaran di balik larangan selimut tersebut, dan kemudian menggunakan fitur bijaksana, dengan pengertian bahwa ada yang banyak situasi yang mereka alat terbaik untuk pekerjaan itu.

"Saya biasanya menghindari jenis casting sebanyak mungkin" adalah contoh yang baik dari aturan yang terlalu umum. Pemeran sangat penting dalam banyak situasi umum. Beberapa contoh:

  1. Saat beroperasi dengan kode pihak ketiga (terutama jika kode itu penuh dengan typedefs). (Contoh: GLfloat<--> double<--> Real.)
  2. Mentransmisikan dari pointer / referensi kelas turunan ke dasar: Ini sangat umum dan alami sehingga kompilator akan melakukannya secara implisit. Jika membuatnya eksplisit meningkatkan keterbacaan, pemeran adalah satu langkah maju, bukan mundur!
  3. Mentransmisikan dari basis ke penunjuk / referensi kelas turunan: Juga umum, bahkan dalam kode yang dirancang dengan baik. (Contoh: wadah heterogen.)
  4. Di dalam serialisasi / deserialisasi biner atau kode level rendah lainnya yang memerlukan akses ke byte mentah dari tipe bawaan.
  5. Kapan saja saat itu lebih alami, nyaman, dan mudah dibaca untuk menggunakan jenis yang berbeda. (Contoh: std::size_type-> int.)

Ada banyak situasi di mana penggunaan cast tidak sesuai, dan penting untuk mempelajarinya juga; Saya tidak akan membahas terlalu banyak detail karena jawaban di atas telah melakukan pekerjaan dengan baik menunjukkan beberapa di antaranya.

pengguna168715
sumber
1

Untuk menguraikan jawaban pengembang KDe , itu tidak inheren dalam tipe aman. Dengan transmisi, tidak ada jaminan bahwa asal dan tujuan transmisi Anda akan cocok, dan jika itu terjadi, Anda akan mendapatkan pengecualian waktu proses, yang selalu merupakan hal yang buruk.

Berkenaan dengan C #, karena termasuk operator isdan as, Anda memiliki kesempatan untuk (sebagian besar) membuat keputusan apakah pemeran akan berhasil atau tidak. Oleh karena itu, Anda harus mengambil langkah-langkah yang tepat untuk menentukan apakah operasi akan berhasil atau tidak dan melanjutkan dengan tepat.

casperOne
sumber
1

Dalam kasus C #, seseorang perlu lebih berhati-hati saat melakukan casting karena overhead tinju / unboxing yang terlibat saat menangani jenis nilai.

Manish Basantani
sumber
1

Tidak yakin apakah seseorang telah menyebutkan ini, tetapi dalam C # casting dapat digunakan dengan cara yang agak aman, dan seringkali diperlukan. Misalkan Anda menerima sebuah objek yang bisa dari beberapa jenis. Dengan menggunakan iskata kunci, Anda dapat terlebih dahulu mengonfirmasi bahwa objek tersebut memang dari tipe yang akan Anda transmisikan, lalu mentransmisikan objek ke tipe itu secara langsung. (Saya tidak banyak bekerja dengan Java tetapi saya yakin ada cara yang sangat mudah untuk melakukannya di sana juga).

pengguna472875
sumber
1

Anda hanya mentransmisikan objek ke beberapa jenis, jika 2 kondisi terpenuhi:

  1. Anda tahu itu jenis itu
  2. kompiler tidak

Ini berarti tidak semua informasi yang Anda miliki terwakili dengan baik dalam tipe struktur yang Anda gunakan. Ini buruk, karena penerapan Anda harus mencakup model Anda secara semantik , yang jelas tidak dalam kasus ini.

Sekarang ketika Anda melakukan cast, ini dapat memiliki 2 alasan berbeda:

  1. Anda melakukan pekerjaan yang buruk dalam mengekspresikan tipe hubungan.
  2. sistem tipe bahasa tidak cukup ekspresif untuk menyusunnya.

Dalam kebanyakan bahasa, Anda sering mengalami situasi ke-2. Generik seperti di Java sedikit membantu, sistem template C ++ bahkan lebih, tetapi sulit untuk dikuasai dan bahkan beberapa hal mungkin tidak mungkin atau tidak sepadan dengan usaha.

Jadi bisa dibilang, pemeran adalah trik kotor untuk menghindari masalah Anda untuk mengekspresikan beberapa jenis hubungan tertentu dalam beberapa bahasa tertentu. Peretasan kotor harus dihindari. Tapi Anda tidak akan pernah bisa hidup tanpanya.

back2dos
sumber
0

Umumnya template (atau generik) lebih aman untuk jenis daripada cast. Dalam hal itu, saya akan mengatakan bahwa masalah dengan casting adalah keamanan tipe. Namun, ada masalah lain yang lebih halus yang terkait terutama dengan downcasting: desain. Setidaknya dari sudut pandang saya, downcasting adalah bau kode, indikasi bahwa ada sesuatu yang salah dengan desing saya dan saya harus menyelidikinya lebih lanjut. Mengapa sederhana: jika Anda "mendapatkan" abstraksi dengan benar, Anda tidak membutuhkannya! Pertanyaan bagus omong-omong ...

Bersulang!

Lefteris Laskaridis
sumber
0

Untuk menjadi sangat ringkas, alasan yang bagus adalah karena portabilitas. Arsitektur berbeda yang mengakomodasi bahasa yang sama mungkin memiliki, katakanlah, ukuran int yang berbeda. Jadi jika saya bermigrasi dari ArchA ke ArchB, yang memiliki int yang lebih sempit, saya mungkin melihat perilaku aneh paling baik, dan seg menyalahkan paling buruk.

(Saya jelas mengabaikan bytecode dan IL independen arsitektur.)

kmarks2
sumber