Mevcut yanıtların tamamının kaçırdığını düşündüğüm bazı önemli konular var.
Zayıf yazma, temeldeki temsile erişimin sağlanması anlamına gelir. C de, karakterlere bir işaretçi oluşturabilir, sonra derleyiciye tamsayılara işaretçi olarak kullanmak istediğimi söyleyebilirim:
char sz[] = "abcdefg";
int *i = (int *)sz;
32 bit tamsayıları olan küçük bir endian platformunda, bu i
sayı 0x64636261
ve bir dizi haline getirir 0x00676665
. Aslında, işaretçileri bile tam sayılara (uygun boyutta) atabilirsiniz:
intptr_t i = (intptr_t)&sz;
Ve elbette bu, sistemin herhangi bir yerinde belleğin üzerine yazabileceğim anlamına geliyor. *
char *spam = (char *)0x12345678
spam[0] = 0;
* Elbette modern işletim sistemleri sanal belleği ve sayfa korumasını kullanıyor, bu yüzden sadece kendi işlemimin belleğinin üzerine yazabiliyorum, ancak C'nin kendisi hakkında kodlanmış olan herkesin söyleyebileceği gibi böyle bir koruma sunan hiçbir şey yok.
Geleneksel Lisp benzer tür bir hackery izin verdi; bazı platformlarda, çift kelimelik yüzer ve eksileri aynı türdeydi ve birini diğerini bekleyen bir işleve geçirebilirdiniz ve "işe yarar".
Bugün çoğu dil C ve Lisp kadar zayıf değil, ancak birçoğu hala biraz sızdı. Örneğin, denetlenmeyen bir "mahzun" olan herhangi bir OO dili, * bu bir tür sızıntıdır: temel olarak derleyiciye "Güvenli olduğunu bilmeniz için yeterli bilgi vermediğimi biliyorum, ama eminim "bir yazım sisteminin asıl amacı derleyicinin neyin güvenli olduğunu bilmek için yeterli bilgiye sahip olmasıdır.
* İşaretli bir downcast, dili çalışma zamanına taşıdığı için dilin tür sistemini daha zayıf yapmaz. Eğer öyleyse, alt tür polimorfizmi (sanal veya tam dinamik fonksiyon çağrıları olarak da bilinir), tip sisteminin aynı ihlali olurdu ve kimsenin bunu söylemek istediğini sanmıyorum.
Çok az sayıda "betik" dili bu anlamda zayıftır. Perl veya Tcl'de bile, bir dize alıp baytlarını bir tamsayı olarak yorumlayamazsınız. * Ancak CPython'da (ve birçok dil için diğer birçok tercüman için), eğer gerçekten ısrar ediyorsanız, kullanabilir ctypes
yüklemek için libpython
, bir nesnenin döküm id
a POINTER(Py_Object)
ve sızıntı tür sistemi zorlar. Bunun tür sistemini zayıflatıp azaltmadığı kullanım durumlarınıza bağlıdır; güvenliği sağlamak için dil kısıtlamalı bir yürütme sanal alanı uygulamaya çalışıyorsanız, bu tür kaçışlarla uğraşmanız gerekir ...
* struct.unpack
Baytları okumak ve "C'nin bu baytları nasıl temsil edeceğinden" yeni bir int oluşturmak gibi bir işlev kullanabilirsiniz , ancak bu açıkça sızıntı yapmaz; Haskell bile buna izin veriyor.
Bu arada, örtük dönüşüm gerçekten zayıf veya sızdıran tip sisteminden farklı bir şeydir.
Her dil, hatta Haskell bile, bir tamsayıyı bir dizgiye veya bir kayan noktaya dönüştürme işlevlerine sahiptir. Ancak bazı diller bu dönüşümlerden bazılarını sizin için otomatik olarak yapar; örneğin, C olarak, bir işlev isteyen bir işlev çağırırsanız float
ve iletirsenizint
, sizin için dönüştürülür. Bu kesinlikle, örneğin beklenmedik taşmalara neden olan hatalara yol açabilir, ancak bunlar zayıf tip bir sistemden aldığınız aynı tür hatalar değildir. Ve C burada gerçekten daha zayıf değil; Haskell'de bir int ve bir şamandıra ekleyebilir veya hatta bir katarı bir dizeye birleştirebilirsiniz, daha açık bir şekilde yapmanız gerekir.
Ve dinamik dillerle, bu oldukça bulanık. Python veya Perl'de "şamandıra isteyen bir işlev" diye bir şey yoktur. Ancak, farklı türlerde farklı şeyler yapan aşırı yüklenmiş işlevler vardır ve örneğin, başka bir şeye dize eklemenin "dize isteyen bir işlev" olduğu konusunda güçlü bir sezgisel his vardır. Bu anlamda, Perl, Tcl ve JavaScript örtülü dönüşüm (bir çok şey gibi görünen "a" + 1
verir "a1"
Python çok az yapar iken (,) "a" + 1
bir özel durum, ama 1.0 + 1
sen veriyor 2.0
*). Bu duyguyu biçimsel terimlere sokmak zordur - neden +
dizinleme gibi başka işlevler varsa, bir dize ve int alan bir şey olmamalı ?
* Aslında, modern Python'da bu, OO alt tipi açısından açıklanabilir, çünkü isinstance(2, numbers.Real)
doğrudur. Ben 2
Perl veya JavaScript dize türü bir örneği olduğu herhangi bir anlamı olduğunu sanmıyorum ... Tcl her ne kadar, aslında, her şey bir dize örneği olduğundan.
Son olarak, "güçlü" ile güçlü / esnek / ifade anlamına gelen "güçlü" ve "zayıf" yazmanın başka, tamamen dikey bir tanımı daha vardır.
Örneğin, Haskell, bir sayı, bir dize, bu tür bir liste veya dizelerden bu türe bir harita olan bir tür tanımlamanıza izin verir; bu, JSON'dan kodu çözülebilecek her şeyi temsil etmenin mükemmel bir yoludur. Java'da böyle bir tür tanımlamanın bir yolu yoktur. Ancak en azından Java'nın parametrik (jenerik) türleri vardır, bu nedenle T Listesi alan bir öğeyi yazabilir ve öğelerin T türünde olduğunu bilirsiniz; erken Java gibi diğer diller sizi bir Nesne Listesi ve mahzun kullanmaya zorladı. Ancak en azından Java, kendi yöntemleriyle yeni türler oluşturmanıza izin verir; C sadece yapılar oluşturmanıza izin verir. BCPL de buna sahip değildi. Ve böylece sadece tiplerin farklı bit uzunlukları olduğu montaja kadar.
Yani, bu anlamda, Haskell'in tip sistemi, önceki Java'lardan daha güçlü olan ve BC'lerden daha güçlü olan C'lerden daha güçlü olan modern Java'lardan daha güçlüdür.
Peki, Python bu spektruma nerede uyuyor? Bu biraz zor. Çoğu durumda, ördek yazmak Haskell'de yapabileceğiniz her şeyi ve hatta yapamayacağınız bazı şeyleri simüle etmenizi sağlar; emin olun, hatalar derleme zamanı yerine çalışma zamanında yakalanır, ancak yine de yakalanırlar. Bununla birlikte, ördek yazmanın yeterli olmadığı durumlar vardır. Örneğin, Haskell'de boş bir ints listesinin bir ints listesi olduğunu söyleyebilirsiniz, böylece +
bu listeyi azaltmanın 0 * döndürmesi gerektiğine karar verebilirsiniz ; Python'da boş bir liste boş bir listedir; azaltmanın ne +
yapması gerektiğine karar vermenize yardımcı olacak tür bilgisi yoktur.
* Aslında, Haskell bunu yapmanıza izin vermiyor; boş bir listede başlangıç değeri almayan azaltma işlevini çağırırsanız bir hata alırsınız. Ancak yazı sistemi, bu işi yapabileceğiniz kadar güçlü ve Python's değil.