Pengetikan Bertahap: “Hampir setiap bahasa dengan sistem tipe statis juga memiliki sistem tipe dinamis”

20

Klaim oleh Aleks Bromfield ini menyatakan:

Hampir setiap bahasa dengan sistem tipe statis juga memiliki sistem tipe dinamis. Selain dari C, saya tidak bisa memikirkan pengecualian

Apakah ini klaim yang valid? Saya mengerti bahwa dengan kelas Refleksi atau Memuat saat runtime Java menjadi sedikit seperti ini - tetapi dapatkah gagasan 'pengetikan bertahap' ini diperluas ke sejumlah besar bahasa?

hawkeye
sumber
Saya bukan ahli bahasa, tetapi beberapa yang langsung terlintas dalam pikiran bahwa saya tidak percaya memiliki tipe yang dinamis (Secara asli, tidak mengatakan Anda tidak dapat menggagalkan sesuatu bersama dalam hal ini) - Fortran, Ada, Pascal, Cobol
mattnz
4
Saya seorang ahli bahasa, dan saya tidak yakin apa yang dikatakan orang ini. "statis" dan "dinamis" adalah misnomer dan biasanya menunjukkan waktu pemeriksaan / analisis tipe (baik pada waktu kompilasi atau saat runtime). Beberapa bahasa menggabungkan keduanya (mis. Dengan melarang operasi pada jenis yang tidak didukung selama kompilasi dan meningkatkan pengecualian seperti ClassCastException selama runtime), dan mungkin itu yang ia maksudkan. Jika demikian, memang benar bahwa C biasanya tidak melakukan pemeriksaan tipe selama runtime. Mengatakan lang. tidak memiliki "sistem tipe dinamis" tidak masuk akal.
Thiago Silva

Jawaban:

37

Tweeter asli di sini. :)

Pertama-tama, saya agak geli / terkejut karena tweet saya dianggap serius! Jika saya tahu ini akan disebar luaskan, saya akan menghabiskan lebih dari 30 detik untuk menulisnya!

Thiago Silva benar untuk menunjukkan bahwa "statis" dan "dinamis" lebih akurat menggambarkan pengecekan tipe , daripada sistem tipe . Bahkan, tidak benar-benar akurat untuk mengatakan bahwa suatu bahasa diketik secara statis atau dinamis. Alih-alih, suatu bahasa memiliki sistem tipe, dan implementasi bahasa itu mungkin memberlakukan sistem tipe menggunakan pemeriksaan statis, atau pemeriksaan dinamis, atau keduanya, atau tidak (meskipun itu tidak akan menjadi implementasi bahasa yang sangat menarik!).

Seperti yang terjadi, ada sistem tipe tertentu (atau fitur sistem tipe) yang lebih dapat menerima pemeriksaan statis, dan ada sistem tipe tertentu (atau fitur sistem tipe) yang lebih dapat menerima pemeriksaan dinamis. Misalnya, jika bahasa Anda memungkinkan Anda untuk menentukan dalam teks suatu program bahwa nilai tertentu harus selalu berupa array bilangan bulat, maka cukup mudah untuk menulis pemeriksa statis untuk memverifikasi properti itu. Sebaliknya, jika bahasa Anda memiliki subtyping, dan jika itu memungkinkan downcasting, maka cukup mudah untuk memeriksa validitas downcast saat runtime, tetapi sangat sulit untuk melakukannya pada waktu kompilasi.

Apa yang saya maksudkan dengan tweet yang saya hanyalah bahwa sebagian besar dari implementasi bahasa melakukan beberapa jumlah memeriksa jenis dinamis. Atau, yang setara, sebagian besar bahasa memiliki beberapa fitur yang sulit (jika bukan tidak mungkin) untuk diperiksa secara statis. Downcasting adalah salah satu contohnya. Contoh lain termasuk overflow aritmatika, pemeriksaan batas array, dan pemeriksaan nol. Beberapa di antaranya dapat diperiksa secara statis dalam beberapa keadaan, tetapi pada umumnya, Anda akan kesulitan menemukan implementasi bahasa yang tidak melakukan pengecekan saat runtime.

Ini bukan hal yang buruk. Itu hanya pengamatan bahwa ada banyak properti menarik yang ingin kita dukung bahasa kita, dan bahwa kita tidak benar-benar tahu cara mengecek secara statis. Dan itu adalah pengingat bahwa perbedaan seperti "tipe statis" versus "tipe dinamis" hampir tidak sejelas yang diyakini oleh beberapa orang. :)

Satu catatan terakhir: istilah "kuat" dan "lemah" tidak benar-benar digunakan dalam komunitas riset bahasa pemrograman, dan mereka tidak benar-benar memiliki makna yang konsisten. Secara umum, saya telah menemukan bahwa ketika seseorang mengatakan bahwa suatu bahasa memiliki "ketikan yang kuat" dan beberapa bahasa lainnya memiliki "ketikan yang lemah", mereka benar-benar mengatakan bahwa bahasa favorit mereka (yang dengan "ketikan yang kuat") mencegah mereka dari membuat beberapa kesalahan bahwa bahasa lain (yang dengan "mengetik lemah") tidak - atau sebaliknya, bahasa favorit mereka (yang dengan "mengetik lemah") memungkinkan mereka untuk melakukan beberapa hal keren bahwa bahasa lain (yang satu dengan "pengetikan kuat") tidak.

Aleks Bromfield
sumber
9
"Ini hanya pengamatan bahwa ada banyak properti menarik yang ingin kita penegakan bahasa kita, dan bahwa kita tidak benar-benar tahu cara mengecek secara statis." - Yah, bukan hanya karena kita tidak tahu bagaimana melakukannya. "Apakah Program berhenti ini untuk masukan ini" adalah properti yang menarik bahwa kita tidak hanya tidak tahu bagaimana untuk memeriksa, tapi sebenarnya kita lakukan tahu adalah mustahil untuk memeriksa.
Jörg W Mittag
"Contoh lain termasuk overflow aritmatika, pemeriksaan batas array, dan pemeriksaan nol." Hanya perhatikan bahwa walaupun ada beberapa bahasa yang memeriksa properti ini dalam sistem tipe, bahkan dalam sebagian besar bahasa yang diketik secara dinamis, ini biasanya merupakan fitur nilai , bukan tipe. (Pemeriksaan "Null" adalah fitur umum dari sistem tipe statis.)
porglezomp
Ada adalah jenis dinamis sistem , dan jenis statis sistem . Bahkan jika tidak ada yang ditegakkan, mereka masih ada di sana, menggambarkan apa yang benar dan apa yang salah. Bahasa / implementasi mungkin atau mungkin tidak memeriksa salah satunya. BTW, sistem tipe statis dan dinamis harus konsisten, tetapi tidak demikian halnya dengan definisi .
Elazar
Setiap bahasa memiliki sistem tipe dinamis, yang merupakan seperangkat aturan yang melarang operasi tertentu dilakukan.
Elazar
7

Baiklah. Anda dapat memiliki tas properti dalam bahasa yang diketik secara statis. Sintaksnya akan mengerikan sementara pada saat yang sama Anda akan mendapatkan semua kelemahan dari sistem yang diketik secara dinamis. Jadi sebenarnya tidak ada keuntungan apa pun kecuali kompiler memungkinkan Anda untuk menggunakan sintaksis yang lebih bagus, sesuatu seperti yang dilakukan oleh C # dynamic.

Anda juga dapat melakukannya dengan mudah di C juga.

Sebagai reaksi terhadap jawaban lain: Saya pikir orang salah mengetik statis / dinamis dengan kuat / lemah mengetik. Pengetikan dinamis adalah tentang kemampuan untuk mengubah struktur data saat runtime dan kode dapat menggunakan data yang hanya sesuai dengan apa yang dibutuhkan oleh kode. Ini disebut Mengetik Bebek .

Menyebutkan refleksi tidak menceritakan keseluruhan cerita, karena refleksi tidak memungkinkan Anda untuk mengubah struktur data yang ada. Anda tidak bisa menambahkan bidang baru ke kelas atau struktur di C, C ++, Java atau C #. Dalam bahasa yang dinamis, menambahkan bidang atau atribut baru ke kelas yang ada tidak hanya mungkin, tetapi sebenarnya sangat umum.

Misalnya, lihat Cython , kompiler Python-ke-C. Ini menciptakan kode C statis, tetapi sistem tipe masih mempertahankan sifat dinamisnya. C adalah bahasa yang diketik secara statis, namun ia dapat mendukung pengetikan dinamis dari Python.

Euforia
sumber
Secara teknis, Anda dapat melakukannya di C # sejak versi 4 ExpandoObject, meskipun sangat banyak proses opt-in, tidak seperti JavaScript atau Ruby. Namun, Anda telah membuat poin yang sangat penting, yaitu mengetik bebek (apa yang sebenarnya berarti 99% pengembang ketika mereka mengatakan "diketik secara dinamis") dan refleksi bukanlah hal yang sama sekali.
Aaronaught
Mungkin saya juga menambahkan bahwa Python tidak memiliki mengetik bebek nyata. Itu hanya memiliki beberapa kait bagi Anda untuk "mengimplementasikan milik Anda" (memiliki metode ajaib yang dapat kembali Trueuntuk mengatakan "objek gila ini adalah turunan dari kelas yang saya definisikan"). OCaml memang memiliki fitur ini sejauh yang saya mengerti, tetapi saya tidak benar-benar tahu.
vlad-ardelean
6

Bahasa dinamis adalah bahasa statis . Apa yang biasa disebut "pengetikan dinamis" sebenarnya adalah kasus khusus pengetikan statis - kasus di mana Anda membatasi diri hanya memiliki satu jenis. Sebagai percobaan pemikiran, bayangkan menulis sebuah program di Java atau C # hanya menggunakan Objectvariabel / bidang / parameter dan down-casting segera sebelum memanggil metode apa pun . Akan lebih akurat untuk memanggil bahasa seperti Python atau Javascript "unityped". (Klaim ini kemungkinan akan membingungkan / mengganggu banyak orang, mengingat program Java atau C # seperti itu akan menggunakan banyak sub-tipe, tetapi itu karena rata-rata bahasa OOP mengonfigurasi jenis dan kelas. Baca posting blog untuk lebih jelasnya.)

Perhatikan bahwa bahkan C memiliki pengetikan "dinamis" - Anda dapat melemparkan penunjuk apa pun ke penunjuk void(dan jika ingatan saya, char) dan kembali lagi. Dan perhatikan, juga, bahwa tidak ada runtime yang memeriksa di sana; jika Anda salah, nikmati perilaku tidak terdefinisi Anda!

Doval
sumber
Tetapi para pemain dilakukan secara statis. Saya gagal melihat bagaimana ini adalah contoh pengetikan dinamis.
Osa
@ Eosa Hanya karena kode mengatakan String foo = (String) baritu tidak berarti itu barsebenarnya a String. Anda hanya bisa tahu itu pada saat run time, jadi saya tidak melihat bagaimana para pemain dilakukan "secara statis".
Doval
Saya tidak setuju dengan ini. Setidaknya dalam Javascript, Anda bisa menambahkan metode dan properti baru ke objek dalam runtime. Di C #, Anda perlu secara eksplisit menggunakan dynamicobjek untuk melakukan ini. Jika Anda mencoba menambahkan properti ke object... well, Anda tidak bisa.
Arturo Torres Sánchez
3

Perbedaan antara pengetikan statis dan dinamis adalah ketika jenis nilai diperiksa: waktu kompilasi vs waktu berjalan. Dalam bahasa di mana nilai membawa tipenya (misalnya objek Java), maka Anda selalu dapat menggunakan pengetikan dinamis bahkan ketika bahasa sebenarnya lebih memilih pengetikan statis. Berikut adalah contoh di Jawa, dengan metode yang diketik secara dinamis:

void horribleJava(List untypedList) {
  for (Object o : untypedList)
    ((SpecificType) o).frobnicate();
}

Perhatikan bagaimana jenis setiap item diperiksa saat runtime. Metode yang diketik secara statis setara adalah:

void goodJava(List<SpecificType> typedList) {
  for (SpecificType o : typedList) {
    o.forbnicate();
  }
}

Di C, nilai (dan khususnya pointer) tidak mempertahankan tipenya selama runtime - setiap pointer setara dengan a void *. Sebagai gantinya, variabel dan ekspresi memiliki tipe. Untuk mencapai pengetikan dinamis, Anda harus membawa sendiri informasi jenis tersebut (misalnya sebagai bidang dalam sebuah struct).

amon
sumber
1
Saya tidak berpikir pemeran dianggap sebagai pengetikan dinamis dalam arti praktis. Itu masih membutuhkan pengetahuan tentang jenis pada waktu kompilasi, itu hanya menolak validasi yang sebenarnya sampai runtime. Anda tidak dapat menggunakan frobnicatemetode ini di sini tanpa mengetahui terlebih dahulu SpecificType.
Aaronaught
2
@Aaronaught Tapi ini adalah mengetik dinamis setelah kami ditangguhkan cek tipe untuk menjalankan waktu. Perhatikan bahwa kedua contoh saya menggunakan pengetikan nominatif yang memerlukan nama jenis tertentu. Anda sedang memikirkan pengetikan struktural , mis. Pengetikan bebek yang memerlukan beberapa metode. Pengetikan struktural vs nominatif dan statis vs dinamis adalah ortogonal satu sama lain (Jawa adalah nominatif dan sebagian besar statis; ML dan Go adalah struktural dan statis; Perl, Python, dan Ruby (sebagian besar) struktural dan dinamis).
amon
Seperti yang saya katakan di komentar terakhir saya, ini adalah perbedaan teoretis bahwa tidak ada programmer yang pernah saya temui yang benar-benar peduli. Anda dapat dengan kasar berdebat bahwa orang-orang menggunakan terminologi yang salah (dan pada kenyataannya memang tampak bahwa tweeter yang asli tepat untuk jenis snarkiness semacam itu) tetapi untuk orang-orang yang benar-benar berada di parit, pengetikan dinamis = pengetikan bebek. Bahkan definisi itu sangat umum sehingga bahasa seperti C # telah benar-benar mengkodifikasinya (yaitu dengan dynamickata kunci). Menyamakan statis untuk waktu kompilasi dan dinamis untuk runtime sebagian besar hanya mengeruhkan air.
Aaronaught
@Aaronaught: Jika seseorang menggunakan antarmuka, dan jika kelas yang mengimplementasikan metode dengan makna yang dimaksud secara konsisten mengimplementasikan antarmuka yang sama untuk mengatakan demikian, maka seseorang pada dasarnya akan menjalankan bebek saat mengetik. Sementara beberapa orang mungkin berpendapat bahwa "bebek mengetik" hanya boleh menggunakan nama metode, saya pikir akan lebih membantu untuk menganggap nama metode "nyata" sebagai nama antarmuka ditambah nama metode. Jika tidak, harus [1,2].Add([3,4])menghasilkan [1,2,3,4], [1,2,[3,4]]atau [4,6]?
supercat
@supercat: Tidak satu pun di atas, itu harus gagal karena tidak ada Addmetode pada array yang menerima array karena metode seperti itu akan ambigu. Mengetik bebek tidak membuat Anda tidak bisa menulis tipe dan fungsi yang bisa dipahami.
Aaronaught
2

Pengetikan statis vs dinamis pada dasarnya mengacu pada bagaimana jenis diperiksa. Pengetikan statis berarti bahwa verifikasi jenis berbagai variabel atau ekspresi diperiksa berdasarkan kode aktual (biasanya oleh kompiler) sementara dalam sistem tipe dinamis verifikasi ini dilakukan hanya pada saat runtime, oleh lingkungan runtime.

Apa yang saya percaya teks merujuk adalah bahwa bahkan jika jenis sebenarnya diperiksa secara statis, mereka juga diperiksa saat runtime, yaitu secara dinamis. Anda menyebutkan Refleksi Java dengan benar; refleksi hanya terjadi saat runtime dan Java Runtime Environment (JVM) benar-benar melakukan pemeriksaan tipe ketika refleksi digunakan, yang pada dasarnya berarti pemeriksaan tipe dinamis.

m3th0dman
sumber
Maka itu tidak benar. Dalam C ++, Pascal, Fortran --- dalam bahasa yang dikompilasi --- jenis hanya diperiksa secara statis, dan tidak secara dinamis (kecuali jika Anda menggunakan dynamic_cast). Anda dapat menggunakan pointer untuk menulis hal-hal yang sewenang-wenang ke memori, dan tidak ada yang akan tahu tipenya. Jadi pengetikan statis berarti HANYA PERIKSA SECARA STATISTIK, sedangkan pengetikan dinamis berarti HANYA PERIKSA DI RUNTIM.
Osa
-1

Pengecualiannya salah: C juga memiliki sistem tipe dinamis yang penting. Itu hanya tidak memeriksanya ("C sangat diketik, lemah diperiksa"). Misalnya, memperlakukan struct sebagai double( reinternpret_cast-style) menghasilkan perilaku yang tidak terdefinisi - kesalahan tipe dinamis.

Elazar
sumber
(Kepada siapa pun yang diturunkan - komentar @Thiago Silva mengatakan tentang hal yang sama)
Elazar