Zayıf yazılan dillerle ilgili belirgin çelişkiler hakkında açıklama istemek


178

Güçlü yazmayı anladığımı düşünüyorum , ancak zayıf yazmanın ne olduğuna ilişkin örnekler aradığımda, türleri otomatik olarak zorlayan / dönüştüren programlama dilleri örnekleri buluyorum.

Örneğin, Yazma: Güçlü ve Zayıf, Statik ve Dinamik adlı bu makalede , aşağıdakileri yapmaya çalışırsanız bir istisna aldığınız için Python'un güçlü bir şekilde yazıldığını söylüyor:

piton

1 + "1"
Traceback (most recent call last):
File "", line 1, in ? 
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Ancak, Java ve C # 'da böyle bir şey mümkündür ve bunların sadece bunun için zayıf yazıldığını düşünmüyoruz.

Java

  int a = 10;
  String b = "b";
  String result = a + b;
  System.out.println(result);

C #

int a = 10;
string b = "b";
string c = a + b;
Console.WriteLine(c);

Weakly Type Languages adlı başka bir makalede yazar, Perl'in zayıf bir şekilde yazıldığını, çünkü herhangi bir açık dönüşüm olmadan bir sayıya ve viceversa'ya bir dizeyi birleştirebileceğimi söylüyor.

Perl

$a=10;
$b="a";
$c=$a.$b;
print $c; #10a

Yani aynı örnek Perl'i zayıf yazmış, ancak Java ve C #? Değil.

Gee, bu kafa karıştırıcı resim açıklamasını buraya girin

Yazarlar, farklı türlerdeki değerlere belirli işlemlerin uygulanmasını engelleyen bir dilin güçlü bir şekilde yazıldığını ve aksine zayıf bir şekilde yazıldığını ifade etmektedir.

Bu nedenle, bir noktada, bir dil, türler arasında çok sayıda otomatik dönüşüm veya zorlama sağlıyorsa (perl olarak) zayıf yazılmış olarak kabul edilebileceğine inanırken, yalnızca birkaç dönüşüm sağlayan diğer dillerin kuvvetle yazılmış sayılır.

Bununla birlikte, bu yorumda yanlış olmam gerektiğine inanmaya meyilliyim, sadece neden veya nasıl açıklayacağımı bilmiyorum.

Yani, sorularım:

  • Bir dilin gerçekten zayıf yazılması gerçekten ne anlama geliyor?
  • Dil tarafından yapılan otomatik dönüşüm / otomatik zorlama ile ilgili olmayan zayıf yazmanın iyi örneklerinden bahsedebilir misiniz?
  • Bir dil aynı anda zayıf ve güçlü bir şekilde yazılabilir mi?

8
Güçlü ve zayıf yazmaya karşı tür dönüştürme (başka ne olabilir?) "Çok" zayıf bir dil örneği istiyorsanız, şunu izleyin: destroyallsoftware.com/talks/wat .
Mart'ta Wilduck

2
@Wildduck Tüm diller tür dönüşümü sağlar, ancak bunların tümü zayıf yazılmış olarak kabul edilmez. Aşağıda gösterilen örneklerim, programcıların, güçlü yazılan diğer dillerde mümkün olan aynı örneklere dayanarak zayıf yazılan bir dili nasıl düşündüklerini göstermektedir. Bu yüzden sorum hala devam ediyor. Fark ne?
Edwin Dalorzo

1
Kısa cevap, bence, "Tipiklik" ikili bir durum değildir. Java ve C # daha güçlü yazılmıştır, ancak kesinlikle değildir.
56'da Jodrell

3
Bunun Yazılım Mühendisliği için daha uygun olduğuna inanıyorum .
zzzzBov

4
@Brendan Bir kayan nokta ve bir tam sayı toplamaya ne dersiniz? Tam sayı Python'da bir kayan noktaya zorlanmaz mı? Şimdi Python'un kesinlikle güçlü bir şekilde yazılmadığını söyleyebilir misiniz?
Edwin Dalorzo

Yanıtlar:


210

GÜNCELLEME: Bu soru, 15 Ekim 2012 tarihinde blogumun konusuydu. Harika soru için teşekkürler!


Bir dilin "zayıf yazılmış" olması gerçekten ne anlama geliyor?

"Bu dil, tatsız bulduğum bir tür sistem kullanıyor" anlamına geliyor. Buna karşılık "kuvvetle yazılmış" bir dil, hoş bulduğum bir yazı sistemine sahip bir dildir.

Terimler aslında anlamsızdır ve onlardan kaçınmalısınız. Wikipedia "güçlü yazılan" için birçoğu çelişkili olan onbir farklı anlam listeler . Bu, "güçlü yazılan" veya "zayıf yazılan" terimini içeren herhangi bir konuşmada yaratılan karışıklık olasılığının yüksek olduğunu gösterir.

Gerçekten kesin olarak söyleyebileceğiniz tek şey, tartışma altındaki "güçlü yazılan" bir dilin, çalışma zamanında veya derleme zamanında tür sisteminde, tartışma altında "zayıf yazılan" bir dilin eksik olduğu bazı ek kısıtlamalar olmasıdır. Bu kısıtlamanın ne olabileceği, başka bir bağlam olmadan belirlenemez.

"Güçlü yazım" ve "zayıf yazım" kullanmak yerine, ne tür bir güvenlik demek istediğinizi ayrıntılı olarak açıklamalısınız. Örneğin, C #, statik olarak yazılan bir dil ve bir tür güvenli dil ve bir bellek güvenli dildir, çoğunlukla. C #, bu "güçlü" yazım biçimlerinin üçünün de ihlal edilmesini sağlar. Döküm operatörü statik yazmayı ihlal eder; derleyiciye "Bu ifadenin çalışma zamanı türü hakkında sizden daha fazla şey biliyorum" der. Geliştirici yanlışsa, çalışma zamanı tür güvenliğini korumak için bir istisna atar. Geliştirici, tip güvenliğini veya bellek güvenliğini kırmak istiyorsa, "güvenli olmayan" bir blok oluşturarak tip güvenliği sistemini kapatarak bunu yapabilir. Güvenli olmayan bir blokta int'i şamandıra (tip güvenliği ihlal eden) olarak tedavi etmek veya sahip olmadığınız belleğe yazmak için işaretçi sihir kullanabilirsiniz. (Bellek güvenliğini ihlal ediyor.)

C #, hem derleme zamanında hem de çalışma zamanında denetlenen tür kısıtlamaları uygular, böylece daha az derleme zamanı denetimi veya daha az çalışma zamanı denetimi yapan dillerle karşılaştırıldığında "güçlü bir şekilde yazılmış" bir dil haline getirir. C # ayrıca, özel durumlarda bu kısıtlamalar etrafında bir son çalıştırma yapmanıza izin verir, bu da bunu böyle bir son çalıştırma yapmanıza izin vermeyen dillerle karşılaştırıldığında "zayıf yazılan" bir dil haline getirir.

Hangisi gerçekten? Söylemek imkansız; konuşmacının bakış açısına ve çeşitli dil özelliklerine karşı tutumlarına bağlıdır.


14
@edalorzo: (1) tip teorisinin hangi yönlerinin alakalı ve hangilerinin alakasız olduğu ve (2) bir dilin tip kısıtlamalarını uygulamak veya sadece teşvik etmek için gerekli olup olmadığı hakkında zevk ve kişisel görüşlere dayanır . Belirttiğim gibi, C # 'nın statik yazmayı izin verdiği ve teşvik ettiği için güçlü bir şekilde yazıldığını söyleyebiliriz ve biri de tür güvenliğini ihlal etme olasılığına izin verdiği için zayıf yazıldığını söyleyebilir .
Eric Lippert

4
@edalorzo: Toplantıya gelince, yine bir fikir meselesi. Bir montaj dili derleyicisi, yığından 64 bit çift 32 bit yazmacı taşımak için izin vermez; 32 bit imleci yığından 64 bit ikiye 32 bit yazmaçına taşımanıza izin verir. Bu anlamda, dil "tipik güvenli" dir - bir tür veri sınıflandırmasına dayalı olarak programın yasallığı konusunda bir kısıtlama getirmektedir. Bu kısıtlamanın "güçlü" veya "zayıf" olup olmadığı bir görüş meselesidir, ancak açıkça bir kısıtlamadır.
Eric Lippert

2
Sanırım şimdi ne demek istediğimi anlıyorum, gerçekten zayıf yazılan bir dilin tamamen türlenmemiş veya tek tipli olması gerekir, ki bu gerçek hayatta neredeyse imkansızdır. Bu nedenle, herhangi bir dilin güvenli olan belirli tür tanımları vardır ve dilin verilerini veya veri türlerini ihlal etmek veya değiştirmek için sağladığı deliklerin sayısına bağlı olarak, daha fazla veya daha az zayıf yazıldığını düşünebilirsiniz. yalnızca belirli bağlamlarda.
Edwin Dalorzo

7
@edalorzo: Doğru. Örneğin, türlenmemiş lambda hesabı, alabileceğiniz kadar zayıf yazılmıştır. Her işlev bir işlevden işleve bir işlevdir; her veri "aynı tipte" olduğu için herhangi bir veri kısıtlama olmaksızın herhangi bir fonksiyona aktarılabilir. Bir ifadenin türlenmemiş lambda hesabındaki geçerliliği, belirli ifadeleri belirli türlere sahip olarak sınıflandıran anlamsal bir analize değil, yalnızca sözdizimsel şekline bağlıdır.
Eric Lippert

3
@ Mark ona herkesin konuyla ilgili farklı yorumlar sağlayacağını tahmin ettiği için bir +1 daha verirdim. Bu "zayıf yazım" bir "efsanevi konsept" ya da "kentsel bir efsane" gibi görünüyor, herkes bunu gördü, ama kimse var olduğunu kanıtlayamıyor :-)
Edwin Dalorzo

64

Diğerlerinin de belirttiği gibi, "güçlü yazılan" ve "zayıf yazılan" terimleri o kadar çok farklı anlama sahiptir ki sorunuzun tek bir cevabı yoktur. Bununla birlikte, sorunuzda Perl'den özellikle bahsettiğiniz için, Perl'in hangi anlamda zayıf yazıldığını açıklamaya çalışalım.

Mesele şu ki, Perl'de "tamsayı değişkeni", "kayan değişken", "dize değişkeni" veya "boolean değişkeni" diye bir şey yoktur. Aslında, kullanıcının söyleyebildiği kadarıyla (genellikle) tamsayı, kayan nokta, dize veya boole değerleri bile yoktur : sahip olduğunuz tek şey, aynı anda bunların hepsi olan "skaler" dir. Böylece, örneğin şunları yazabilirsiniz:

$foo = "123" + "456";           # $foo = 579
$bar = substr($foo, 2, 1);      # $bar = 9
$bar .= " lives";               # $bar = "9 lives"
$foo -= $bar;                   # $foo = 579 - 9 = 570

Tabii ki, doğru bir şekilde not ettiğiniz gibi, tüm bunlar sadece tip zorlaması olarak görülebilir. Ancak mesele şu ki, Perl'de türler her zaman zorlanıyor. Aslında, bir kullanıcının bir değişkenin dahili "tipinin" ne olabileceğini söylemesi oldukça zordur: yukarıdaki örneğimdeki 2. satırda, değerinin $bardize "9"mi yoksa sayı mı olduğunu sormak 9oldukça anlamsızdır, çünkü Perl söz konusu olduğunda, bunlar aynı şeydir . Aslında, bir Perl skalerinin dahili olarak hem bir dize hem de bir sayısal değere sahip olması , örneğin $fooyukarıdaki 2. satırdan sonra olduğu gibi bile mümkündür .

Tüm bunların tersi, Perl değişkenleri türetilmediğinden (ya da daha ziyade, dahili türlerini kullanıcıya maruz bırakmadığından), operatörlerin farklı argüman türleri için farklı şeyler yapmak için aşırı yüklenememesidir; "bu işleç sayılar için X, dizeler için Y yapacak" diyemezsiniz, çünkü işleç, bağımsız değişkenlerinin ne tür değerler olduğunu söyleyemez (söylemez).

Bu nedenle, örneğin, Perl hem bir sayısal toplama operatörüne ( +) hem de bir dize birleştirme operatörüne ( .) sahiptir ve ihtiyaç duyar : yukarıda gördüğünüz gibi, dizeler ( "1" + "2" == "3") eklemek veya sayıları ( 1 . 2 == 12) birleştirmek mükemmeldir . Benzer şekilde, sayısal karşılaştırma operatörleri ==, !=, <, >, <=, >=ve <=>onların argümanları sayısal değerleri karşılaştırmak, dize karşılaştırma operatörleri ise eq, ne, lt, gt, le, geve cmpdizeleri olarak sözlük sırasında onları karşılaştırın. Yani 2 < 10, ama 2 gt 10(ama "02" lt 10, süre "02" == 2). (Dikkat edin, JavaScript gibi bazı diğer diller, Perl benzeri zayıf yazmayı kabul etmeye çalışın.ayrıca operatör aşırı yüklenmesi yapıyor. Bu genellikle çirkinliğe yol açar, örneğin ilişkilendirilebilirlik kaybı gibi +.)

(Buradaki merhemdeki sinek, tarihsel nedenlerden ötürü, Perl 5'in, davranışlarının argümanlarının iç temsiline bağlı olan bitsel mantıksal operatörler gibi birkaç köşe vakası olduğu. Bunlar genellikle can sıkıcı bir tasarım hatası olarak kabul edilir. iç temsil şaşırtıcı nedenlerle değişebilir ve bu nedenle belirli bir durumda bu operatörlerin ne yaptığını tahmin etmek zor olabilir.)

Hepsi bir Perl iddia olabilir, söz konusu yapar güçlü türleri vardır; onlar sadece beklediğiniz türden türler değildir. Spesifik olarak, yukarıda tartışılan "skaler" tipine ek olarak, Perl ayrıca iki yapısal tipe sahiptir: "dizi" ve "karma". Bunlar, skalerlerden, Perl değişkenlerinin tiplerini gösteren farklı imzalara sahip oldukları noktaya kadar çok farklıdır ( skalerler, diziler için, karmalar için) 1 . Orada olan bu kadar bu tür arasındaki zorlama kuralları, olabilir mesela yazmak , ama bunların çoğu oldukça kayıplı: örneğin, atar uzunluğu dizinin etmek$@%%foo = @bar$foo = @bar@bar$foo, içeriği değil. (Ayrıca, genellikle maruz kalmadığını görmediğiniz, yazıtipleri ve G / Ç tutamaçları gibi birkaç garip tür vardır.)

Ayrıca, bu güzel tasarımda hafif bir çığlık, özel bir skaler tür olan (ve operatörü kullanarak normal skalerlerden ayırt edilebilen) referans türlerinin varlığıdır ref. Referansları normal skaler olarak kullanmak mümkündür, ancak dize / sayısal değerleri özellikle kullanışlı değildir ve normal skaler işlemleri kullanarak değiştirirseniz özel referanslarını kaybetme eğilimindedirler. Ayrıca, herhangi bir Perl değişkeni 2 , blessbir sınıfa dönüştürülerek o sınıfın bir nesnesine dönüştürülebilir; Perl'deki OO sınıf sistemi, yukarıda açıklanan ilkel tip (veya tipsizlik) sistemine biraz dikeydir, ancak ördek tipini takip etme anlamında da "zayıf" dır.paradigması. Genel görüş şu ki, eğer Perl'de bir nesnenin sınıfını kontrol ederseniz, yanlış bir şey yapıyorsunuzdur.


1 Aslında, sigil erişilen değerin türünü belirtir, böylece dizideki ilk skaler @foogösterilir $foo[0]. Daha fazla bilgi için perlfaq4'e bakınız.

2 Perl'deki nesnelere (normalde) bunlara yapılan başvurular yoluyla erişilir, ancak gerçekte blessed olan şey referansın işaret ettiği (muhtemelen anonim) değişkendir. Bununla birlikte, nimet aslında değerinin değil , değişkenin bir özelliğidir, örneğin gerçek kutsanmış değişkeni bir başkasına atamak size sadece sığ ve kutsanmamış bir kopyasını verir. Daha fazla bilgi için perlobj'ye bakınız.


19

Eric'in söylediklerine ek olarak, aşağıdaki C kodunu göz önünde bulundurun:

void f(void* x);

f(42);
f("hello");

Python, C #, Java veya whatnot gibi dillerin aksine, tür bilgilerini kaybettiğimiz için yukarıdakiler zayıf yazılmıştır . Eric, doğru bir şekilde C # 'da derleyiciyi dökerek atlatabildiğimizi ve etkili bir şekilde “Bu değişkenin türü hakkında sizden daha fazla şey biliyorum” diyebileceğimize dikkat çekti.

Ama o zaman bile, çalışma zamanı hala türü kontrol edecek! Oyuncular geçersizse, çalışma zamanı sistemi onu yakalar ve bir istisna atar.

Tür silme ile bu gerçekleşmez - tür bilgisi atılır. void*C'ye yapılan bir oyuncu tam olarak bunu yapar. Bu bağlamda, yukarıdaki gibi bir C # yöntemi bildiriminden temelde farklıdır void f(Object x).

(Teknik olarak, C # ayrıca güvenli olmayan kod veya sıralama ile tür silinmesine de izin verir.)

Bu , olabildiğince zayıf yazılmıştır. Geri kalan her şey sadece statik veya dinamik tip kontrolü, yani bir türün kontrol edildiği zaman meselesidir .


1
+1 İyi bir nokta, şimdi bana tip silmeyi "zayıf tipleme" anlamına da gelebilecek bir özellik olarak düşündürttün. Java'da da tür silme vardır ve çalışma zamanında tür sistemi derleyicinin asla onaylamayacağı kısıtlamaları ihlal etmenize izin verir. C örneği noktayı göstermek için mükemmeldir.
Edwin Dalorzo

1
Kabul, soğan veya cehennem katmanları vardır. Bunlar tip zayıflığının daha önemli bir tanımı gibi görünüyor.
Jodrell

1
@edalorzo ben bu olduğunu sanmıyorum oldukça Java Eğer derleyici tuzağa sağlar olsa bile, çalışma zamanı tür sistemi hala ihlali yakalayacak beri aynı. Bu nedenle Java çalışma zamanı türü sistemi bu bağlamda güçlü bir şekilde yazılmıştır (istisnalar vardır, örneğin yansımanın erişim kontrolünü atlatmak için kullanılabileceği yerler).
Konrad Rudolph

1
@edalorzo Derleyiciyi yalnızca bu şekilde atlatabilirsiniz, çalışma zamanı sistemini değil. Java ve C # (ve bir dereceye kadar C ++) gibi dillerin, bir kez derleme zamanında ve bir kez çalışma zamanında olmak üzere iki kez sağlanan bir tür sisteme sahip olduğunu fark etmek önemlidir. void*her iki tür denetimi de sonlandırır. Genel tip silme sadece derleme zamanı kontrollerini atlatır. Tam olarak bu konuda (Eric tarafından belirtilen) açık oyuncular gibi.
Konrad Rudolph

1
@edalorzo Yeniden karışıklığınız: Yapmamalıyız. Ayrım akıcı. Ve evet, tür silme Java'yı bu konuda zayıf yazıyor. Anlatmak bile genel tür silme ile bu oldu hala zamanı tür kontrollerinden kaçınmak olamaz da yansıması kullanmak sürece .
Konrad Rudolph

14

Mükemmel bir örnek Strong Typing'in wikipedia makalesinden gelir :

Genel olarak güçlü yazım, programlama dilinin, karışmasına izin verilen karışmaya ciddi kısıtlamalar getirdiğini gösterir.

Zayıf Yazma

a = 2
b = "2"

concatenate(a, b) # returns "22"
add(a, b) # returns 4

Güçlü Yazma

a = 2
b = "2"

concatenate(a, b) # Type Error
add(a, b) # Type Error
concatenate(str(a), b) #Returns "22"
add(a, int(b)) # Returns 4

Zayıf bir yazma dilinin farklı türleri hatasız karıştırabileceğine dikkat edin. Güçlü bir dil, giriş türlerinin beklenen tür olmasını gerektirir. Güçlü bir yazım dilinde bir tür dönüştürülebilir ( str(a)bir tamsayıyı dizeye dönüştürür) veya cast ( int(b)).

Bu, yazmanın yorumlanmasına bağlıdır.


3
Ancak bu, soruda belirtilen çelişkili örneklere yol açar. Güçlü Yazılan bir dil, iki "Tür Hatası" örneğinizden birinin (veya her ikisinin) otomatik olarak ikinci iki örneğin ilgiliine dönüştürüldüğü anlamına gelen örtülü zorlamayı içerebilir, ancak genellikle bu dil hala Güçlü Yazılmıştır.
Mark Hurd

3
Doğru. Sanırım farklı derecelerde güçlü yazma ve zayıf yazma olduğunu söyleyebilirsiniz. Örtük dönüşüm, dilin örtük dönüşüm yapmayan bir dilden daha az güçlü yazıldığı anlamına gelebilir.
SaulBack

4

Konuyla ilgili kendi araştırmamla tartışmaya katkıda bulunmak istiyorum, diğerleri yorum yaparken ve katkıda bulunduğumda cevaplarını okuyorum ve referanslarını takip ediyorum ve ilginç bilgiler buldum. Önerildiği gibi, bunların çoğunun Programcılar forumunda daha iyi tartışılması muhtemeldir, çünkü pratikten daha teorik görünmektedir.

Teorik açıdan, Luca Cardelli ve Peter Wegner'ın Türleri Anlama, Veri Soyutlama ve Çok Biçimlilik Üzerine adlı makalesinde okuduğum en iyi argümanlardan biri olduğunu düşünüyorum.

Bir tip, altta yatan tipsiz bir temsili keyfi veya istenmeyen kullanımdan koruyan bir giysi seti (veya bir zırh takımı) olarak görülebilir . Temel temsili gizleyen ve nesnelerin diğer nesnelerle etkileşime girme biçimini kısıtlayan koruyucu bir kaplama sağlar. Türlenmemiş bir sistemde, türlenmemiş nesneler , altta yatan temsilin herkesin görmesi için açığa çıkması nedeniyle çıplaktır . Tip sistemini ihlal etmek, koruyucu kıyafet setinin çıkarılmasını ve doğrudan çıplak temsil üzerinde çalışmayı içerir.

Bu ifade, zayıf yazmanın bir türün iç yapısına erişmemize ve onu başka bir şeymiş gibi (başka bir tür) değiştirmemize izin vereceğini düşündürmektedir. Belki güvenli olmayan kodla (Eric tarafından bahsedilir) ya da Konrad tarafından belirtilen c tipi silinmiş işaretçilerle neler yapabiliriz.

Makale devam ediyor ...

Tüm ifadelerin yazım tutarlı olduğu diller, güçlü yazılan diller olarak adlandırılır. Bir dil kuvvetle yazılırsa, derleyicisi kabul ettiği programların tür hatası olmadan yürütülmesini garanti edebilir. Genel olarak, güçlü yazım için çaba göstermeli ve mümkün olduğunda statik yazmayı benimsemeliyiz. Statik olarak yazılan her dilin güçlü bir şekilde yazıldığını, ancak tersinin mutlaka doğru olmadığını unutmayın.

Bu nedenle, güçlü yazma, tip hatalarının olmaması anlamına gelir, sadece zayıf yazmanın aksine anlamına geldiğini varsayabilirim: tip hatalarının olası varlığı. Çalışma zamanında mı derleme zamanı mı? Burada anlamsız görünüyor.

Bu tanıma göre komik bir şey, Perl gibi güçlü tip zorlamalara sahip bir dilin güçlü bir şekilde yazıldığı kabul edilir, çünkü sistem başarısız değildir, ancak bunları uygun ve iyi tanımlanmış eşdeğerlere zorlayarak türlerle ilgilenir.

Öte yandan, ClassCastExceptionve ArrayStoreException(Java'da) ödeneği dışında söyleyebilir miyim InvalidCastException,ArrayTypeMismatchException derleme zamanında en azından zayıf yazarak bir seviyeye işaret edebilecektir (C #)? Eric'in cevabı buna katılıyor gibi görünüyor.

Bu sorunun cevaplarından birinde verilen referanslardan birinde sağlanan Tipik Programlama adlı ikinci bir makalede Luca Cardelli, tip ihlalleri kavramını araştırıyor:

Çoğu sistem programlama dili, bazıları gelişigüzel, bazıları ise yalnızca programın sınırlı bölümlerinde rastgele tür ihlallerine izin verir. Tip ihlallerini içeren operasyonlara ses denir. Tip ihlalleri birkaç sınıfta kalmaktadır [bunlardan bahsedebiliriz]:

Temel değer zorlamaları : Bunlar, tamsayılar, booleanlar, karakterler, kümeler, vb.

Bu nedenle, operatörler tarafından sağlananlar gibi tip zorlamaları tip ihlalleri olarak kabul edilebilir, ancak tip sisteminin tutarlılığını bozmadıkça, zayıf tiplendirilmiş bir sisteme yol açmadıklarını söyleyebiliriz.

Buna dayanarak Python, Perl, Java veya C # zayıf yazılmaz.

Cardelli, gerçekten zayıf yazım vakalarını çok iyi düşündüğüm iki tip viyalasyondan bahsediyor:

Adres aritmetiği. Gerekirse, adresler ve tür dönüşümleri üzerinde yeterli işlemleri sağlayan yerleşik (sağlam olmayan) bir arayüz olmalıdır. Çeşitli durumlar, yığının içine işaretçiler (toplayıcıların yerini değiştirmekle çok tehlikelidir), yığına işaretçiler, statik alanlara işaretçiler ve diğer adres alanlarına işaretçiler içerir. Bazen dizi indeksleme adres aritmetiğinin yerini alabilir. Bellek eşleme. Bu, yapılandırılmış veriler içermesine rağmen, bellek alanına yapılandırılmamış bir dizi olarak bakmayı içerir. Bu, bellek ayırıcılar ve toplayıcılar için tipiktir.

C (Konrad tarafından belirtilen) veya .Net'teki (Eric tarafından bahsedilen) güvenli olmayan kodlar gibi dillerde mümkün olan bu tür şeyler gerçekten zayıf yazmayı ima eder.

Şimdiye kadarki en iyi yanıtın Eric olduğuna inanıyorum, çünkü bu kavramların tanımı çok teoriktir ve belirli bir dile gelince, tüm bu kavramların yorumları farklı tartışmalı sonuçlara yol açabilir.


4

Zayıf yazım, kodlayıcının ne istediğini tahmin etmeye çalışırken, yüksek oranda türün dolaylı olarak zorlanabileceği anlamına gelir.

Güçlü yazma, türlerin zorlanmadığı veya en azından daha az zorlanmadığı anlamına gelir.

Statik yazma, değişkenlerinizin türlerinin derleme zamanında belirlendiği anlamına gelir.

Son zamanlarda birçok insan "açıkça yazılan" ile "güçlü yazılan" kelimesini karıştırmaktadır. "Manifestly typed", değişkenlerinizin türlerini açıkça beyan ettiğiniz anlamına gelir.

Python çoğunlukla güçlü bir şekilde yazılmıştır, ancak boolean bağlamında hemen hemen her şeyi kullanabilirsiniz ve boolelar tamsayı bağlamında kullanılabilir ve kayan bağlamda bir tamsayı kullanabilirsiniz. Açıkça yazılmamıştır, çünkü türlerinizi beyan etmenize gerek yoktur (ilginç de olsa, tamamen python olmayan Cython hariç). Ayrıca statik olarak yazılmaz.

C ve C ++ açıkça yazılır, statik olarak yazılır ve biraz kuvvetle yazılır, çünkü türlerinizi beyan edersiniz, türler derleme zamanında belirlenir ve tamsayıları ve işaretçileri, tamsayıları ve çiftleri karıştırabilir veya hatta bir işaretçiyi bir türe çevirebilirsiniz başka bir tür gösterici.

Haskell ilginç bir örnektir, çünkü açıkça yazılmamıştır, ancak aynı zamanda statik ve güçlü bir şekilde yazılmıştır.


+1 Java ve C # gibi dilleri kategorilere açık bir şekilde bildirmeniz ve bunları tür çıkarımının önemli bir rol oynadığı Haskell ve Scala gibi diğer statik tip dillerden ayırmanız gereken kategorileri "açıkça yazılan" teriminden hoşlandığım için dediğiniz gibi insanları karıştırır ve bu dillerin dinamik olarak yazıldığına inandırır.
Edwin Dalorzo

3

Güçlü <=> zayıf yazma sadece değerlerin bir veri tipinin dili tarafından otomatik olarak ne kadar veya ne kadar az otomatik olarak zorlandığı değil, aynı zamanda gerçek değerlerin ne kadar güçlü veya zayıf bir şekilde yazıldığıyla ilgili süreklilikle ilgilidir . Python ve Java'da ve çoğunlukla C #'da, değerlerin türleri taş olarak ayarlanır. Perl'de, çok fazla değil - bir değişkente depolamak için gerçekten sadece bir avuç farklı değer türü var.

Vakaları tek tek açalım.


piton

Python örneğinde 1 + "1", +işleç , dizeyi bağımsız değişken olarak veren __add__for türünü çağırır - ancak bu NotImplemented ile sonuçlanır:int"1"

>>> (1).__add__('1')
NotImplemented

Ardından, tercüman str'yi dener __radd__:

>>> '1'.__radd__(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__radd__'

Başarısız olduğu için, +operatör sonuçta başarısız olur TypeError: unsupported operand type(s) for +: 'int' and 'str'. Bu nedenle, istisna güçlü yazım hakkında fazla bir şey söylemez, ancak operatörün argümanlarını otomatik olarak aynı türe + zorlamaması , Python'un süreklilikteki en zayıf yazılan dil olmadığı gerçeğinin bir göstergesidir.

Öte yandan, Python 'a' * 5 edilir uygulanan:

>>> 'a' * 5
'aaaaa'

Yani,

>>> 'a'.__mul__(5)
'aaaaa'

İşlemin farklı olması, güçlü bir yazım gerektirir - ancak *değerleri çarpmadan önce sayılara zorlamanın tersi , değerleri mutlaka zayıf yazmaz.


Java

Java örneği, String result = "1" + 1;yalnızca kolaylık olması nedeniyle, işleç +dizeler için aşırı yüklü olduğu için çalışır. Java +operatör oluşturma dizisini değiştirir StringBuilder(bakınız bu ):

String result = a + b;
// becomes something like
String result = new StringBuilder().append(a).append(b).toString()

Bu, gerçek bir baskı olmaksızın çok statik yazmanın bir örneğidir - burada özellikle kullanılan StringBuilderbir yöntem append(Object)vardır. Belgeler aşağıdakileri söylüyor:

Bağımsız Objectdeğişkenin dize olarak temsilini ekler .

Genel etki, tam olarak, argüman yöntemle bir dizeye dönüştürülmüş String.valueOf(Object)ve bu dizenin karakterleri daha sonra bu karakter dizisine eklenmiştir.

Nerede String.valueOfo zaman

Object bağımsız değişkeninin dize olarak temsilini döndürür. [Döndürür] argüman ise null, o zaman "null"; aksi takdirde değeri obj.toString()döndürülür.

Bu nedenle, bu dil tarafından kesinlikle hiçbir zorlama yoktur - her kaygıyı nesnelerin kendisine devreder.


C #

Buradaki Jon Skeet cevabına göre , operatör sınıf +için aşırı yüklenmiyor string- Java'ya benzer, bu hem derleyici tarafından üretilen, hem statik hem de güçlü yazma sayesinde kolaylık.


Perl

Gibi perldata açıklıyor

Perl'in üç dahili veri türü vardır: skalerler, skaler dizileri ve "hash" olarak bilinen skalerlerin ilişkili dizileri. Skaler, tek bir dize (herhangi bir boyutta, yalnızca kullanılabilir bellekle sınırlıdır), sayı veya bir şeye referanstır (perlref'de tartışılacaktır). Normal diziler, 0 ile başlayarak sayı ile indekslenen skaler listeleridir. Karmalar, ilişkili dize anahtarıyla indekslenen skaler değerlerin sırasız koleksiyonlarıdır.

Bununla birlikte Perl, sayılar, booleans, dize, null, undefineds, diğer nesnelere referanslar vb. İçin ayrı bir veri türüne sahip değildir - bu hepsi için tek bir türü vardır, skaler tip; 0, "0" kadar skaler bir değerdir. Dize olarak ayarlanmış bir skaler değişken gerçekten bir sayıya dönüşebilir ve sayısal bir bağlamda erişilirse oradan "sadece bir dize" den farklı şekilde davranabilir. Skaler Perl'de herhangi bir şeyi tutabilir, sistemde var olduğu kadar nesnedir. Python'da isimler sadece nesnelere atıfta bulunurken, Perl'de isimlerdeki skaler değerler değiştirilebilir nesnelerdir. Ayrıca, Nesneye Dayalı Tip sistemi bunun üzerine yapıştırılmıştır: perller, listeler ve karmalarda sadece 3 veri türü vardır. Perl'deki kullanıcı tanımlı bir nesne, bir referanstır (önceki 3'ten herhangi birine bir işaretçi)blessBir pakette düzenlenir - böyle bir değeri alabilir ve istediğiniz anda herhangi bir sınıfa kutlayabilirsiniz.

Perl bile kapıda değer sınıflarını değiştirmenize izin verir - bu, Python'da, o sınıfa ait object.__new__veya benzer bir değeri açıkça oluşturmak için ihtiyacınız olan bazı sınıfların bir değerini oluşturmak için mümkün değildir . Python'da yaratılıştan sonra nesnenin özünü gerçekten değiştiremezsiniz, Perl'de çok şey yapabilirsiniz:

package Foo;
package Bar;

my $val = 42;
# $val is now a scalar value set from double
bless \$val, Foo;
# all references to $val now belong to class Foo
my $obj = \$val;
# now $obj refers to the SV stored in $val
# thus this prints: Foo=SCALAR(0x1c7d8c8)
print \$val, "\n"; 
# all references to $val now belong to class Bar
bless \$val, Bar;
# thus this prints Bar=SCALAR(0x1c7d8c8)
print \$val, "\n";
# we change the value stored in $val from number to a string
$val = 'abc';
# yet still the SV is blessed: Bar=SCALAR(0x1c7d8c8)
print \$val, "\n";
# and on the course, the $obj now refers to a "Bar" even though
# at the time of copying it did refer to a "Foo".
print $obj, "\n";

bu nedenle tip kimliği değişkene zayıf bir şekilde bağlanır ve anında herhangi bir referansla değiştirilebilir. Aslında, eğer yaparsan

my $another = $val;

\$another\$valkutsanmış referansı vermesine rağmen, sınıf kimliğine sahip değildir .


TL; DR

Perl'e zayıf yazmayla ilgili otomatik zorlamalardan çok daha fazlası var ve dinamik olarak çok güçlü bir şekilde yazılmış bir dil olan Python'dan farklı olarak değerlerin türlerinin taşa yerleştirilmemesi daha fazla. Bu piton verir TypeErrorüzerindeki 1 + "1"Java veya C # gibi yararlı bir şey yapma aykırı bir, kesinlikle yazılı dilleri olmak onları engellemez rağmen, dil kesinlikle yazılı olduğu bir göstergesidir.


Bu tamamen karışık. Perl 5 değişkenlerinin tip içermemesi , her zaman bir tipe sahip değerler üzerinde herhangi bir etkiye sahip değildir .
Jim Balter

@JimBalter iyi, evet, bir değerin bir dize veya sayı olması bakımından bir türü vardır ve skaler değişkenin bir dize veya sayı içermesine bağlı olarak bazı bağlamlarda farklı davranabilir; ama değeri sadece değişken erişerek türünü değiştirebilirsiniz bir değişken bulunan ve değerin kendisi yaşar beri içinde değişken değerleri kendileri türleri arasında değişken olarak kabul edilebilir.
Antti Haapala

Değerler türleri değiştirmez - bu tutarsızdır; bir değer her zaman bir türdedir . Bir değişkenin içerdiği değer değişebilir. 1'den "1" e bir değişiklik, 1'den 2'ye bir değişiklik kadar değerde bir değişikliktir.
Jim Balter

Perl gibi zayıf yazılan bir dil , bağlama bağlı olarak önceki türdeki değer değişikliğinin örtük olarak gerçekleşmesini sağlar. Ancak C ++ bile bu tür örtük dönüşümlere operatör tanımları aracılığıyla izin verir. Zayıf yazım gayri resmi bir özelliktir ve Eric Lippert'in işaret ettiği gibi, dilleri tanımlamak için gerçekten yararlı bir yol değildir.
Jim Balter

PS Perl'de bile <digits> ve "<digits>" in sadece farklı tiplerde değil, farklı değerlere sahip olduğu gösterilebilir. Perl, <digits> ve "<digits>" ifadelerinin çoğu durumda örtük dönüşümlerle aynı değere sahip görünmesini sağlar , ancak illüzyon tamamlanmamıştır; örneğin "12" | "34" 36, 12 | 34, 46'dır. Başka bir örnek, "00" ın sayısal olarak çoğu bağlamda 00'a eşit olması, ancak boolean bağlamında olmaması, burada "00" doğru fakat 00'ın yanlış olmasıdır.
Jim Balter

1

Diğerlerinin de ifade ettiği gibi, "güçlü" ve "zayıf" yazım kavramının tamamı sorunludur.

Bir arketip olarak, Smalltalk çok güçlü bir şekilde yazılmıştır - iki nesne arasındaki bir işlem uyumsuzsa her zaman bir istisna oluşturur. Ancak, bu listedeki birkaç kişinin Smalltalk'a güçlü bir şekilde yazılan bir dil diyeceğini düşünüyorum, çünkü dinamik olarak yazılmıştır.

"Statik" ve "dinamik" yazım kavramını "güçlü" ve "zayıf" tan daha yararlı buluyorum. Statik olarak yazılan bir dil, derleme zamanında anlaşılan tüm türlere sahiptir ve programcı aksi takdirde açıkça bildirmelidir.

Yazma işleminin çalışma zamanında yapıldığı dinamik olarak yazılan bir dille kontrast. Bu genellikle polimorfik diller için bir gerekliliktir, bu nedenle iki nesne arasındaki bir işlemin yasal olup olmadığına ilişkin kararların programcı tarafından önceden kararlaştırılması gerekmez.

Polimorfik, dinamik olarak yazılan dillerde (Smalltalk ve Ruby gibi), bir "türü" bir "protokole uygunluk" olarak düşünmek daha yararlıdır. Bir nesne bir protokole başka bir nesne ile aynı şekilde uyuyorsa - iki nesne herhangi bir miras veya mixin veya başka bir voodoo paylaşmasa bile - çalışma zamanı sistemi tarafından aynı "tip" olarak kabul edilir. Daha doğrusu, bu tür sistemlerde bir nesne özerktir ve herhangi bir belirli argümana atıfta bulunan belirli bir mesaja cevap vermenin mantıklı olup olmadığına karar verebilir.

Mavi rengi tanımlayan bir nesne argümanı ile "+" mesajına anlamlı bir cevap verebilecek bir nesne ister misiniz? Bunu dinamik olarak yazılmış dillerde yapabilirsiniz, ancak statik olarak yazılmış dillerde bir acıdır.


3
Dinamik ve statik yazım kavramlarının tartışılmadığını düşünüyorum. Her ne kadar polimorfizmin statik tip dilde özürlü olduğuna inanmadığımı söylememe rağmen. Sonuçta, tür sistemi, belirli bir işlemin çalışma zamanında veya derleme zamanında verilen işlenenler için geçerli olup olmadığını doğrular. Ayrıca, parametrik fonksiyonlar ve sınıflar gibi diğer polimorfizm biçimleri, statik olarak yazılan dillerdeki türleri, dinamik olarak yazılana kıyasla çok zor olarak tanımladığınız şekilde birleştirmenize izin verir, hatta tür çıkarım sağlanırsa daha da güzeldir.
Edwin Dalorzo

0

@Eric Lippert'in cevabını seviyorum , ancak soruyu ele almak için - güçlü yazılan diller genellikle programın her bir noktasında değişken türleri hakkında net bilgiye sahiptir. Zayıf yazılan diller çalışmaz, bu nedenle belirli bir tür için mümkün olmayan bir işlem gerçekleştirmeye çalışabilirler. Bunu görmenin en kolay yolunun bir fonksiyonda olduğunu düşünüyorum. C ++:

void func(string a) {...}

Değişkenin adize türü olduğu bilinmektedir ve uyumsuz herhangi bir işlem derleme zamanında yakalanacaktır.

Python:

def func(a)
  ...

Değişken aherhangi bir şey olabilir ve yalnızca çalışma zamanında yakalanacak geçersiz bir yöntem çağıran bir kodumuz olabilir.


12
Dinamik yazımla statik yazmayı, güçlü yazmayı ve zayıf yazmayı karıştırıyor olabileceğinizi düşünüyorum. Kodunuzun her iki sürümünde, çalışma zamanı türü sistemleri a'nın bir dize olduğunu çok iyi bilir. Sadece ilk durumda, derleyici size söyleyebilir, ikincisinde yapamaz. Ancak bu, bu dillerden hiçbirini zayıf yazmaz.
Edwin Dalorzo
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.