Saya hanya memperhatikan bahwa setiap bahasa pemrograman OO modern yang paling tidak saya kenal (yang pada dasarnya hanya Java, C # dan D) memungkinkan array kovarian. Artinya, array string adalah array objek:
Object[] arr = new String[2]; // Java, C# and D allow this
Array kovarian adalah lubang pada sistem tipe statis. Mereka membuat kesalahan tipe mungkin yang tidak dapat dideteksi pada waktu kompilasi, jadi setiap penulisan ke array harus diperiksa saat runtime:
arr[0] = "hello"; // ok
arr[1] = new Object(); // ArrayStoreException
Sepertinya ini adalah kinerja yang buruk jika saya melakukan banyak toko array.
C ++ tidak memiliki array kovarian, jadi tidak perlu melakukan pemeriksaan runtime, yang berarti tidak ada penalti kinerja.
Apakah ada analisis yang dilakukan untuk mengurangi jumlah pemeriksaan runtime yang diperlukan? Misalnya, jika saya katakan:
arr[1] = arr[0];
orang bisa berpendapat bahwa toko itu tidak mungkin gagal. Saya yakin ada banyak kemungkinan optimasi lain yang belum saya pikirkan.
Apakah kompiler modern benar-benar melakukan optimasi semacam ini, atau apakah saya harus hidup dengan kenyataan bahwa, misalnya, Quicksort selalu melakukan O (n log n) pemeriksaan runtime yang tidak perlu?
Bisakah bahasa OO modern menghindari overhead yang dibuat dengan mendukung array co-varian?
Jawaban:
D tidak memiliki array kovarian. Itu memungkinkan mereka sebelum rilis terbaru ( dmd 2.057 ), tetapi bug itu telah diperbaiki.
Array dalam D secara efektif hanya sebuah struct dengan sebuah pointer dan panjang:
Pemeriksaan batas dilakukan secara normal ketika mengindeks array, tetapi dihapus ketika Anda kompilasi
-release
. Jadi, dalam mode rilis, tidak ada perbedaan kinerja nyata antara array di C / C ++ dan yang di D.sumber
T[dim]
dapat implisit dikonversi ke salah satu dari berikut: ...U[]
... Sebuah array dinamisT[]
dapat implisit dikonversi ke salah satu dari berikut:U[]
. .. dimanaU
kelas dasar dariT
. "const U[]
, sejak itu Anda tidak dapat menetapkan jenis yang salah untuk elemen array, tetapiT[]
pasti tidak akan dikonversiU[]
selamaU[]
dapat diubah. Mengizinkan array kovarian seperti yang dilakukannya sebelumnya adalah cacat desain serius yang sekarang telah diperbaiki.Ya, satu optimasi penting adalah ini:
Di C #, kelas ini tidak bisa menjadi supertipe untuk tipe apa pun, jadi Anda bisa menghindari pemeriksaan untuk array tipe
Foo
.Dan untuk pertanyaan kedua, dalam F # co-varian array tidak diperbolehkan (tapi saya rasa cek akan tetap di CLR kecuali ditemukan tidak perlu dalam optimasi saat runtime)
https://stackoverflow.com/questions/7339013/array-covariance-in-f
Masalah yang agak terkait adalah memeriksa array terikat. Ini mungkin merupakan bacaan yang menarik (tetapi lama) tentang optimisasi yang dilakukan di CLR (kovarians juga disebutkan 1 tempat): http://blogs.msdn.com/b/clrcodegeneration/archive/2009/08/13/array-bounds -check-eliminasi-di-the-clr.aspx
sumber
val a = Array("st"); val b: Array[Any] = a
ilegal. (Namun, array di Scala adalah ... sihir khusus ... karena JVM yang mendasarinya digunakan.)Jawaban Jawa:
Saya kira Anda belum benar-benar membandingkan kode, bukan? Secara umum 90% dari semua gips dinamis di Jawa adalah gratis karena JIT dapat mengeliminasi mereka (quicksort harus menjadi contoh yang baik untuk ini) dan sisanya adalah satu
ld/cmp/br
urutan yang benar-benar dapat diprediksi (jika tidak, mengapa juga kode Anda melemparkan semua pengecualian pemeran dinamis itu?).Kami melakukan pemuatan jauh lebih awal daripada perbandingan yang sebenarnya, cabang diprediksi dengan benar di 99,9999% (dibuat statistik!) Dari semua kasus sehingga kami tidak menghentikan pipa (dengan asumsi kami tidak menekan memori dengan beban, jika tidak baik itu akan terlihat, tetapi kemudian beban diperlukan bagaimanapun). Karenanya biayanya adalah 1 siklus clock JIKA JIT tidak bisa menghindari cek sama sekali.
Beberapa overhead? Tentu, tapi saya ragu Anda akan menyadarinya ..
Untuk membantu mendukung jawaban saya, silakan lihat blogpost Dr. Cliff Click ini membahas kinerja Java vs C.
sumber
D tidak mengizinkan array kovarian.
Seperti yang Anda katakan, itu akan menjadi lubang di sistem tipe untuk memungkinkan ini.
Anda dapat dimaafkan atas kesalahan tersebut, karena bug ini baru saja diperbaiki pada DMD terbaru, dirilis pada 13 Desember.
Akses array di D sama cepatnya dengan di C atau C ++.
sumber
Dari tes yang saya lakukan pada laptop murah, perbedaan antara menggunakan
int[]
danInteger[]
sekitar 1,0 ns. Perbedaannya mungkin karena pemeriksaan tambahan untuk jenisnya.Umumnya Objek hanya digunakan untuk logika tingkat yang lebih tinggi ketika tidak setiap ns diperhitungkan. Jika Anda perlu menyimpan setiap ns, saya akan menghindari penggunaan konstruksi tingkat tinggi seperti Objects. Tugas saja cenderung menjadi faktor yang sangat kecil dalam setiap program nyata. misalnya membuat Obyek baru pada mesin yang sama adalah 5 ns.
Panggilan untuk membandingkanKemungkinan jauh lebih mahal, terutama jika Anda menggunakan objek kompleks seperti String.
sumber
Anda bertanya tentang bahasa OO modern lainnya? Nah, Delphi menghindari masalah ini sepenuhnya dengan
string
menjadi primitif, bukan objek. Jadi array string adalah array string dan tidak ada yang lain, dan operasi apa pun pada mereka secepat kode asli, tanpa jenis memeriksa overhead.Namun, array string jarang digunakan; Pemrogram Delphi cenderung menyukai
TStringList
kelas. Untuk jumlah overhead yang minimal, ia menyediakan serangkaian metode string-group yang berguna dalam banyak situasi sehingga kelasnya telah dibandingkan dengan Knife Swiss Army. Jadi itu idiomatis untuk menggunakan objek daftar string daripada array string.Adapun objek lain secara umum, masalahnya tidak ada karena di Delphi, seperti di C ++, array tidak kovarian, untuk mencegah jenis lubang sistem jenis yang dijelaskan di sini.
sumber
Kinerja CPU tidak monoton, yang berarti bahwa program yang lebih lama bisa lebih cepat daripada yang lebih pendek (ini tergantung CPU, dan itu berlaku untuk arsitektur x86 dan amd64 yang umum). Jadi ada kemungkinan bahwa sebuah program melakukan pengecekan terikat pada array sebenarnya lebih cepat daripada program yang disimpulkan dari sebelumnya dengan menghapus pengecekan terikat ini.
Alasan perilaku ini adalah pengecekan terikat memodifikasi penyelarasan kode dalam memori, akan memodifikasi frekuensi hit cache, dll.
Jadi ya, hiduplah dengan fakta bahwa Quicksort selalu melakukan O (n log n) pemeriksaan palsu dan mengoptimalkan setelah profil.
sumber
Scala adalah bahasa OO yang memiliki array yang invarian, bukan kovarian. Ini menargetkan JVM, jadi tidak ada kinerja yang menang di sana, tetapi menghindari kesalahan umum untuk Java dan C # yang membahayakan keamanan tipe mereka untuk alasan kompatibilitas ke belakang.
sumber