Java'nın türlerini silmenin faydaları nelerdir?


98

Bugün şöyle bir tweet okudum :

Java kullanıcılarının tür silme işleminden şikayet etmeleri komiktir ki bu, Java'nın yanlış yaptığı her şeyi görmezden gelirken doğru yaptığı tek şeydir.

Dolayısıyla sorum şu:

Java'nın tür silmesinin faydaları var mı? Geriye dönük uyumluluk ve çalışma zamanı performansı için JVM uygulamaları tercihi dışında (muhtemelen) sunduğu teknik veya programlama stili avantajları nelerdir?


6
Sorunuzun "fikir temelli" olarak kapatılmasını istemiyorsanız, farklı şekilde sormalısınız. ("Tür silmenin teknik avantajları nelerdir" gibi). Daha da iyisi, tweeter'a gerçekte ne dediğini sorun.
Stephen C

3
"Bu neden iyi bir şey" i kaldırın. "İyi şey" açıkça öznel bir karakterizasyondur ve (açık bir şekilde) tür silme işleminin iyi bir şey olduğu sorusunu akla getirir ...
Stephen C

3
Bu site, Twitter'da şimdiye kadar yayınlanan her şeyle ilgili sorulara dönüşecekse Tanrı bize yardım etsin. En azından sorunuz için saygın bir kaynağı belirtin.
Lorne Markisi

21
Sorunun neden "itibarlı kaynaktan" olması gerekiyor? Bu çok aptalca.
vertti

4
Pekala, buradaki sorunların çoğu HERHANGİ bir kaynaktan değil, soru soranların belirli bir yazılım / dil / başka bir şeyle ilgili sorunları var ve neyse ki bu insanlara yardım etmek için zamanlarını "boşa harcayan" birçok profesyonel var.
vertti

Yanıtlar:


90

Tür Silme İyi

Gerçeklere bağlı kalalım

Şimdiye kadarki cevapların çoğu, Twitter kullanıcısı ile aşırı derecede ilgileniyor. Haberciye değil mesajlara odaklanmak faydalı olacaktır. Şimdiye kadar bahsedilen alıntılarla bile oldukça tutarlı bir mesaj var:

Java kullanıcılarının tür silme işleminden şikayet etmeleri komiktir ki bu, Java'nın yanlış yaptığı her şeyi görmezden gelirken doğru yaptığı tek şeydir.

Büyük faydalar (örneğin parametriklik) ve sıfır maliyet (iddia edilen maliyet hayal gücümün bir sınırıdır) elde ediyorum.

yeni T bozuk bir programdır. "Bütün önermeler doğrudur" iddiası izomorfiktir. Ben bu kadar büyük değilim.

Bir hedef: makul programlar

Bu tweetler, makineye bir şey yaptırıp yaptıramayacağımızla ilgilenmeyen bir perspektifi yansıtıyor , daha çok, makinenin gerçekten istediğimiz bir şeyi yapmasını isteyip istemediğimizle ilgileniyor . İyi muhakeme bir kanıttır. Kanıtlar resmi gösterimle veya daha az resmi bir şekilde belirtilebilir. Şartname diline bakılmaksızın, açık ve titiz olmaları gerekir. Resmi olmayan spesifikasyonların doğru şekilde yapılandırılması imkansız değildir, ancak pratik programlamada genellikle kusurludur. Resmi olmayan muhakeme ile karşılaştığımız sorunları telafi etmek için otomatik ve keşif testleri gibi iyileştirmeler yapıyoruz. Bu, testin özünde kötü bir fikir olduğu anlamına gelmez, ancak alıntı yapılan Twitter kullanıcısı çok daha iyi bir yol olduğunu öne sürüyor.

Dolayısıyla amacımız, makinenin programı gerçekte nasıl çalıştıracağına karşılık gelecek şekilde açık ve titiz bir şekilde akıl yürütebileceğimiz doğru programlara sahip olmaktır. Yine de tek amaç bu değil. Ayrıca mantığımızın bir dereceye kadar anlamlı olmasını da istiyoruz. Örneğin, önermesel mantıkla ifade edebileceğimiz çok şey var. Birinci dereceden mantık gibi bir şeyden evrensel (∀) ve varoluşsal (∃) nicelemeye sahip olmak güzel.

Muhakeme için tip sistemlerini kullanma

Bu hedefler, tip sistemler tarafından çok güzel bir şekilde ele alınabilir. Bu, özellikle Curry-Howard yazışmaları nedeniyle nettir . Bu uyuşma genellikle aşağıdaki benzetmeyle ifade edilir: teoremler ispat için olduğu gibi türler programlardır.

Bu yazışma biraz derin. Mantıksal ifadeler alabilir ve bunları yazışmalar yoluyla türlere çevirebiliriz. Daha sonra, derleyen aynı tip imzaya sahip bir programımız varsa, mantıksal ifadenin evrensel olarak doğru olduğunu (bir totoloji) kanıtlamış oluruz. Bunun nedeni, yazışmanın iki yönlü olmasıdır. Tür / program ve teorem / ispat dünyaları arasındaki dönüşüm mekaniktir ve çoğu durumda otomatikleştirilebilir.

Curry-Howard, bir programın spesifikasyonlarıyla yapmak istediklerimizi güzel bir şekilde oynuyor.

Tür sistemleri Java'da kullanışlı mı?

Curry-Howard anlayışına rağmen, bazı insanlar bir tür sistemin değerini göz ardı etmeyi kolay buluyor.

  1. çalışmak son derece zor
  2. (Curry-Howard aracılığıyla) sınırlı ifade gücüne sahip bir mantığa karşılık gelir
  3. bozuk (sistemlerin "zayıf" veya "güçlü" olarak nitelendirilmesine ulaşır).

İlk noktaya gelince, belki de IDE'ler Java'nın yazı sistemini çalışmayı yeterince kolaylaştırır (bu oldukça özneldir).

İkinci nokta ile ilgili olarak, Java neredeyse birinci dereceden bir mantığa karşılık gelir. Jenerikler, evrensel nicelemenin tip sistemi eşdeğerini kullanır. Ne yazık ki, joker karakterler bize varoluşsal niceliğin yalnızca küçük bir bölümünü verir. Ancak evrensel niceleme oldukça iyi bir başlangıçtır. Tüm olası listeler List<A>için evrensel olarak çalıştığını söyleyebilmek güzel çünkü A tamamen sınırsızdır. Bu, Twitter kullanıcısının "parametriklik" açısından ne hakkında konuştuğuna götürür.

Parametriklik hakkında sık sık alıntılanan bir makale, Philip Wadler'in Teoremleridir! . Bu makaleyle ilgili ilginç olan şey, sadece tip imzasından yola çıkarak, bazı çok ilginç değişmezleri kanıtlayabilmemizdir. Bu değişmezler için otomatik testler yazacak olsaydık, zamanımızı çok boşa harcardık. Örneğin, List<A>yalnızca tür imzasındanflatten

<A> List<A> flatten(List<List<A>> nestedLists);

buna sebep olabiliriz

flatten(nestedList.map(l -> l.map(any_function)))
    ≡ flatten(nestList).map(any_function)

Bu basit bir örnek ve muhtemelen gayri resmi olarak akıl yürütebilirsiniz, ancak bu tür kanıtları resmi olarak tür sisteminden ücretsiz olarak aldığımızda ve derleyici tarafından kontrol edildiğinde daha da güzel.

Silmemek kötüye kullanımlara yol açabilir

Dil uygulaması perspektifinden bakıldığında, Java'nın jenerikleri (evrensel türlere karşılık gelir), programlarımızın ne yaptığına dair kanıtlar elde etmek için kullanılan parametrikliğe çok fazla etki eder. Bu, bahsedilen üçüncü soruna ulaşır. Tüm bu kanıt ve doğruluk kazanımları, hatasız uygulanan sağlam bir sistem gerektirir. Java, muhakememizi parçalamamıza izin veren bazı dil özelliklerine kesinlikle sahiptir. Bunlar aşağıdakileri içerir ancak bunlarla sınırlı değildir:

  • harici bir sistemle yan etkiler
  • yansıma

Silinmemiş jenerikler birçok yönden yansıma ile ilgilidir. Silinmeden, algoritmalarımızı tasarlamak için kullanabileceğimiz uygulama ile taşınan çalışma zamanı bilgisi vardır. Bunun anlamı, statik olarak, programlar hakkında mantık yürüttüğümüzde, resmin tamamına sahip değilizdir. Düşünme, statik olarak akıl yürüttüğümüz herhangi bir ispatın doğruluğunu ciddi şekilde tehdit eder. Tesadüf değil yansıması, çeşitli hileli kusurlara da yol açar.

Öyleyse silinmemiş jeneriklerin "yararlı" olabileceği yollar nelerdir? Tweet'te bahsedilen kullanımı düşünelim:

<T> T broken { return new T(); }

T'nin argüman içermeyen bir kurucusu yoksa ne olur? Bazı dillerde aldığınız şey boştur. Ya da belki boş değeri atlarsınız ve doğrudan bir istisna oluşturmaya gidersiniz (null değerler yine de sonuçlanır gibi görünür). Dilimiz Turing tamamlandığından, hangi çağrıların broken"güvenli" türleri içereceği ve argümansız kurucularla hangilerinin olmayacağı hakkında mantık yürütmek imkansızdır . Programımızın evrensel olarak çalıştığına dair kesinliği yitirdik.

Silme, gerekçelendirdiğimiz anlamına gelir (öyleyse hadi silelim)

Bu nedenle, programlarımız hakkında mantık yürütmek istiyorsak, muhakememizi şiddetle tehdit eden dil özelliklerini kullanmamamız şiddetle tavsiye edilir. Bunu yaptıktan sonra, o zaman neden türleri çalışma zamanında bırakmıyoruz? Bunlara gerek yok. Hiçbir yayınlamanın başarısız olmayacağı veya yöntemlerin çağrı üzerine eksik olabileceği memnuniyetiyle biraz verimlilik ve basitlik elde edebiliriz.

Silme akıl yürütmeyi teşvik eder.


7
Bu yanıtı bir araya getirmeye başladığım zaman, başka insanlar da benzer yanıtlarla yanıt verdiler. Ama bu kadarını yazdıktan sonra, onu atmak yerine yayınlamaya karar verdim.
Sukant Hajra

34
Bu bağlamda, tür silme, geriye dönük uyumluluğu bozmadan Java'ya bir özellik getirmeye yönelik yarım yamalak bir girişimdi. Bu bir güç değil. En büyük endişe parametresiz kurucuya sahip olmayan bir nesneyi başlatmaya çalışmanız olsaydı, doğru cevap bir dil özelliğini sakatlamak değil, "parametresiz kuruculara sahip türler" kısıtlamasına izin vermektir.
Temel

5
Temel, saygıyla, tutarlı bir tartışma yapmıyorsun. Programlar hakkında akıl yürütmek için zorlayıcı bir araç olarak derleme zamanı provalarının değerini tamamen göz ardı ederek silme işleminin "sakatlayıcı" olduğunu iddia ediyorsunuz. Dahası, bu faydalar Java'nın jenerikleri uygulamak için aldığı çarpık yol ve motivasyonun tamamen ortogonalidir. Ayrıca, bu faydalar çok daha aydınlanmış silme uygulaması olan diller için geçerlidir.
Sukant Hajra

46
Burada sunulan argüman silmeye karşı değildir, yansımaya (ve genel olarak çalışma zamanı tip kontrolüne) aykırıdır - temelde yansımanın kötü olduğunu iddia eder, dolayısıyla silme işleminin onlarla iyi oynamaması gerçeği iyidir. Bu başlı başına geçerli bir noktadır (çoğu insan aynı fikirde olmasa da); ancak bağlam açısından pek bir anlam ifade etmiyor, çünkü Java zaten yansıma / çalışma zamanı kontrollerine sahip ve yok olmadılar ve gitmeyecekler. Yani dilin bu mevcut olmayan kaldırılan kısmı ile oynamaz bir yapı olması ise bir sınırlama, sen nasıl baktığınıza olursa olsun.
Pavel Minaev

10
Cevabınız konu dışı. Soyut bir kavram olarak tür silme işleminin neden genellikle tür sistemlerinin tasarımında yararlı olduğuna dair uzun soluklu (kendi terimleriyle ilginç olsa da) bir açıklama girersiniz, ancak konu, "tür silme" etiketli Java Generics'in belirli bir özelliğinin faydasıdır. ", tanımladığınız kavrama yalnızca yüzeysel olarak benzeyen, ilginç değişmezleri sağlamada tamamen başarısız olan ve mantıksız kısıtlamalar getiren.
Marko Topolnik

41

Türler, derleyicinin bir programın doğruluğunu kontrol etmesine izin verecek şekilde programları yazmak için kullanılan bir yapıdır. Bir tür, bir değer üzerindeki bir önermedir - derleyici bu önermenin doğru olduğunu doğrular.

Bir programın yürütülmesi sırasında tip bilgisine ihtiyaç olmamalıdır - bu zaten derleyici tarafından doğrulanmıştır. Derleyici, kod üzerinde optimizasyonlar gerçekleştirmek için bu bilgileri serbest bırakmalıdır - daha hızlı çalışmasını sağlayın, daha küçük bir ikili dosya oluşturun vb. Tür parametrelerinin silinmesi bunu kolaylaştırır.

Java, tür bilgilerinin çalışma zamanında sorgulanmasına izin vererek statik yazmayı bozar - yansıma, örnek vb. Bu, statik olarak doğrulanamayan programlar oluşturmanıza olanak tanır - tür sistemini atlarlar. Ayrıca, statik optimizasyon fırsatlarını da kaçırır.

Tip parametrelerinin silinmesi gerçeği, bu hatalı programların bazı örneklerinin inşa edilmesini engeller, ancak daha fazla tip bilgisi silinirse ve tesislerin yansıması ve örneği kaldırılırsa daha fazla yanlış programa izin verilmez.

Bir veri türünün "parametriklik" özelliğini korumak için silme önemlidir. Bileşen türü T üzerinden parametrelendirilmiş bir "Liste" türüne sahip olduğumu varsayalım. Örneğin, Liste <T>. Bu tür, bu Liste türünün herhangi bir T türü için aynı şekilde çalıştığına dair bir önermedir.T'nin soyut, sınırsız bir tür parametresi olması, bu tür hakkında hiçbir şey bilmediğimiz anlamına gelir, bu nedenle özel T durumları için özel bir şey yapmamız engellenir.

Örneğin, bir List xs = asList ("3") olduğunu varsayalım. Bir eleman ekliyorum: xs.add ("q"). ["3", "q"] ile bitirdim. Bu parametrik olduğundan, List xs = asList (7) olduğunu varsayabilirim; xs.add (8) [7,8] ile biter Türünden String için bir şey ve Int için bir şey yapmadığını biliyorum.

Dahası, List.add işlevinin havadan T değerlerini icat edemediğini biliyorum. AsList'ime ("3") eklenen bir "7" varsa, olası tek yanıtın "3" ve "7" değerlerinden oluşturulacağını biliyorum. Listeye "2" veya "z" eklenmesi olasılığı yoktur çünkü işlev onu inşa edemeyecektir. Bu diğer değerlerin hiçbirinin eklenmesi mantıklı olmaz ve parametriklik, bu yanlış programların inşa edilmesini engeller.

Temel olarak, silme, parametrikliği ihlal eden bazı araçları engeller, böylece statik yazmanın amacı olan yanlış program olasılıklarını ortadan kaldırır.


15

(Her ne kadar burada bir cevap yazmış olsam da, iki yıl sonra bu soruyu tekrar gözden geçirdiğimde, onu cevaplamanın başka, tamamen farklı bir yolu olduğunu fark ediyorum, bu yüzden önceki cevabı olduğu gibi bırakıyorum ve bunu ekliyorum.)


Java Generics üzerinde yapılan işlemin "tür silme" adını hak edip etmediği oldukça tartışmalıdır. Jenerik tipler silinmediğinden ham muadilleri ile değiştirildiğinden, daha iyi bir seçim "tip bozma" olarak görünmektedir.

Tip silmenin genel olarak anlaşılan en önemli özelliği, çalışma zamanını, eriştiği verilerin yapısına "kör" hale getirerek statik tip sisteminin sınırları içinde kalmaya zorlamasıdır. Bu, derleyiciye tam güç verir ve yalnızca statik türlere dayalı teoremleri kanıtlamasına izin verir. Ayrıca, programcıya kodun serbestlik derecelerini kısıtlayarak ve basit akıl yürütmeye daha fazla güç vererek yardımcı olur.

Java'nın tür silme işlemi bunu başaramaz - aşağıdaki örnekte olduğu gibi derleyiciyi sakat bırakır:

void doStuff(List<Integer> collection) { 
}

void doStuff(List<String> collection) // ERROR: a method cannot have 
                   // overloads which only differ in type parameters

(Yukarıdaki iki bildirim, silme işleminden sonra aynı yöntem imzasına çöker.)

Diğer taraftan, çalışma zamanı hala bir nesnenin türünü ve bunun nedenini inceleyebilir, ancak gerçek türe ilişkin içgörüsü silme nedeniyle sakatlandığından, statik tür ihlallerinin elde edilmesi önemsizdir ve engellenmesi zordur.

İşleri daha da karmaşık hale getirmek için, orijinal ve silinmiş tip imzaları bir arada bulunur ve derleme sırasında paralel olarak değerlendirilir. Bunun nedeni, tüm sürecin çalışma zamanından tür bilgisinin kaldırılması değil, geriye dönük uyumluluğu korumak için genel bir tür sistemi eski bir ham tür sisteme sokmakla ilgili olmasıdır. Bu mücevher klasik bir örnektir:

public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)

( extends ObjectSilinen imzanın geriye dönük uyumluluğunu korumak için yedek eklenmelidir.)

Şimdi, bunu akılda tutarak, alıntıyı tekrar gözden geçirelim:

Java kullanıcılarının tür silme konusunda şikayet etmeleri komik, ki bu Java'nın haklı olduğu tek şey

Java tam olarak neyi doğru yaptı? Anlamı ne olursa olsun kelimenin kendisi mi? Bunun aksine, mütevazı inttüre bir göz atın : hiçbir çalışma zamanı türü denetimi gerçekleştirilmez, hatta mümkün değildir ve yürütme her zaman mükemmel bir şekilde tür açısından güvenlidir. İşte en ne tür silme doğru yapılması zaman gibi görünüyor: hatta orada olduğunu bilmiyoruz.


10

Burada hiç dikkate almadığım tek şey, OOP'nin çalışma zamanı polimorfizminin temelde çalışma zamanında türlerin şeyleştirilmesine bağlı olmasıdır. Omurgası yenilenen türler tarafından yerinde tutulan bir dil, tür sistemine büyük bir uzantı getirdiğinde ve onu tür silmeye dayandırdığında, bilişsel uyumsuzluk kaçınılmaz sonuçtur. Java topluluğunun başına gelen tam olarak buydu; tür silme işleminin bu kadar çok tartışmaya neden olmasının ve nihayetinde Java'nın gelecekteki bir sürümünde bunu geri alma planlarının olmasının nedeni budur . Java kullanıcılarının bu şikayetinde komik bir şey bulmak , ya Java'nın ruhunun dürüst bir şekilde yanlış anlaşılmasına ya da bilinçli olarak küçümseyen bir şakaya ihanet eder.

"Silme, Java'nın doğru yaptığı tek şeydir" iddiası, "çalışma zamanı tipi işlev argümanına karşı dinamik gönderime dayalı tüm dillerin temelde kusurlu olduğu" iddiasını ifade eder. Kesinlikle kendi başına meşru bir iddia ve hatta Java dahil tüm OOP dillerinin geçerli bir eleştirisi olarak kabul edilebilecek bir iddia olsa da , çalışma zamanı polimorfizminin olduğu Java bağlamındaki özellikleri değerlendirmek ve eleştirmek için kendisini önemli bir nokta olarak öne süremez. aksiyomatiktir.

Özetle, geçerli bir şekilde "tür silme, dil tasarımında gitmenin yoludur" şeklinde ifade edilebilirken, Java'daki tür silmeyi destekleyen pozisyonlar, bunun için çok, çok geç olduğu ve hatta tarihsel anda bile çoktan olduğu için yanlış yerleştirilmiştir. Oak, Sun tarafından benimsendiğinde ve Java olarak yeniden adlandırıldığında.



Statik yazmanın kendisinin programlama dillerinin tasarımında doğru yön olup olmadığına gelince, bu, programlama etkinliğini oluşturduğunu düşündüğümüz şeyin çok daha geniş bir felsefi bağlamına uyar . Açıkça klasik matematik geleneğinden türeyen bir düşünce okulu, programları bir matematiksel kavramın veya diğerinin (önermeler, işlevler, vb.) Örnekleri olarak görür, ancak programlamayı bir yol olarak gören tamamen farklı bir yaklaşım sınıfı vardır. makineyle konuşun ve ondan ne istediğimizi açıklayın. Bu görüşe göre, program dinamik, organik olarak büyüyen bir varlıktır, statik olarak yazılmış bir programın dikkatlice oluşturulmuş aedefice'ının dramatik bir zıttıdır.

Dinamik dilleri bu yönde bir adım olarak görmek doğal görünebilir: Programın tutarlılığı, onu yukarıdan aşağıya empoze edecek hiçbir önsel zorunluluk olmadan aşağıdan yukarıya çıkar . Bu paradigma, biz insanların gelişim ve öğrenme yoluyla olduğumuz şey haline geldiği süreci modellemeye doğru bir adım olarak görülebilir.


Bunun için teşekkürler. Bu soru için görmeyi umduğum, dahil olan felsefelerin tam olarak daha derinlemesine anlaşılmasıdır.
Daniel Langdon

Dinamik gönderim, reified türlere hiçbir şekilde bağımlı değildir. Genellikle programlama literatürünün "etiketler" olarak adlandırdığı şeye dayanır, ancak o zaman bile etiketleri kullanması gerekmez. Bir arabirim oluşturursanız (bir nesne için) ve bu arabirimin anonim örneklerini oluşturursanız, o zaman yeniden biçimlendirilmiş türlere gerek kalmadan dinamik dağıtım yaparsınız.
Sukant Hajra

@sukanthajra Bu sadece saç bölünmesi. Etiketi, örneğin sergilediği davranış türünü çözmek için ihtiyaç duyduğunuz çalışma zamanı bilgisidir. Statik tip sistemin ulaşamayacağı bir yerdedir ve tartışılan kavramın özü budur.
Marko Topolnik

Tam olarak bu mantık için tasarlanmış, "toplam türü" adı verilen çok statik bir tür vardır. Aynı zamanda "varyant türü" olarak da adlandırılır (Benjamin Pierce'ın çok iyi Türler ve Programlama Dilleri kitabında). Yani bu hiç de saç kırılması değil. Ayrıca, tamamen etiketsiz bir yaklaşım için bir katamorfizm / katlama / ziyaretçi kullanabilirsiniz.
Sukant Hajra

Teori dersi için teşekkür ederim ama alaka düzeyini göremiyorum. Konumuz Java'nın tip sistemidir.
Marko Topolnik

9

Aynı kullanıcı tarafından aynı görüşmede sonraki bir gönderi:

yeni T bozuk bir programdır. "Tüm önermeler doğrudur" iddiası izomorfiktir. Ben bu kadar büyük değilim.

(Bu, başka bir kullanıcının bir ifadesine, yani "bazı durumlarda 'yeni T' daha iyi gibi görünüyor" ifadesine yanıt olarak yapıldı, fikir new T(), tür silme nedeniyle imkansızdır. (Bu tartışmalıdır - hatta Tmevcut olsa bile . runtime, soyut bir sınıf veya arabirim olabilir veya olabilir Voidveya arg no-arg yapıcısı olmayabilir veya arg no kurucusu özel olabilir (örneğin, bir singleton sınıfı olması gerektiği için) veya no-arg kurucusu, genel yöntemin yakalamadığı veya belirtmediği kontrol edilmiş bir istisna belirtebilirdi - ama öncül buydu. Ne olursa olsun, silme olmadan en azından yazabileceğiniz doğrudur.T.class.newInstance() , bu sorunları .))

Türlerin önermelere eşbiçimli olduğuna dair bu görüş, kullanıcının biçimsel tip teorisinde bir geçmişe sahip olduğunu göstermektedir. (S) büyük olasılıkla "dinamik türleri" veya "çalışma zamanı türlerini" sevmez ve aşağı yayınlar instanceofve yansıma vb. İçermeyen bir Java'yı tercih eder . (Çok zengin (statik) bir sisteme sahip olan ve dinamik semantiği herhangi bir tür bilgisine bağlı olmayan Standard ML gibi bir dil düşünün.)

Bu arada, kullanıcının trol yaptığı akılda tutulmaya değer: Muhtemelen içtenlikle (statik olarak) yazılmış dilleri tercih ederken , bu görüşe diğerlerini içtenlikle ikna etmeye çalışmıyor . Daha ziyade, orijinal tweet'in asıl amacı, aynı fikirde olmayanlarla alay etmekti ve bu fikir ayrılıklarından bazılarının söyledikten sonra, kullanıcı "java'nın tür silme işleminin nedeni, Wadler ve diğerlerinin java kullanıcılarının aksine yapıyorlar ". Ne yazık ki bu, gerçekte ne düşündüğünü bulmayı zorlaştırıyor; ama neyse ki, aynı zamanda bunu yapmanın çok da önemli olmadığı anlamına da geliyor. Onların görüşlerine gerçek derinliği olan kişiler genellikle troller çare yok oldukça bu içerik içermez.


2
Tür silme özelliğine sahip olduğu için Java'da
derlenmiyor

1
@MarkRotteveel: Teşekkürler; Bunu açıklamak (ve yorumlamak) için bir paragraf ekledim.
ruakh

1
Olumlu oylar ve olumsuz oyların karışımına bakılırsa, bu şimdiye kadar gönderdiğim en tartışmalı cevap. Garip bir şekilde gurur duyuyorum.
ruakh

6

İyi bir şey, jenerikler piyasaya sürüldüğünde JVM'yi değiştirmeye gerek olmamasıdır. Java, jenerikleri yalnızca derleyici düzeyinde uygular.


1
JVM neye göre değişir? Şablonlarda da JVM değişiklikleri gerekmez.
Marquis of Lorne

5

Tür silme işleminin iyi bir şey olmasının nedeni, imkansız kılan şeylerin zararlı olmasıdır. Çalışma zamanında tür bağımsız değişkenlerinin incelenmesini önlemek, programların anlaşılmasını ve muhakemesini kolaylaştırır.

Biraz sezgisel bulduğum bir gözlem, işlev imzaları daha genel olduğunda anlaşılmasının daha kolay hale gelmesidir. Bunun nedeni, olası uygulamaların sayısının azalmasıdır. Hiçbir yan etkisi olmadığını bildiğimiz bu imzaya sahip bir yöntemi düşünün:

public List<Integer> XXX(final List<Integer> l);

Bu işlevin olası uygulamaları nelerdir? Çok sayıda. Bu işlevin ne yaptığı hakkında çok az şey söyleyebilirsiniz. Giriş listesini ters çeviriyor olabilir. Girişleri bir araya getirmek, toplamak ve yarısı boyutunda bir liste döndürmek olabilir. Hayal edilebilecek birçok başka olasılık var. Şimdi düşünün:

public <T> List<T> XXX(final List<T> l);

Bu işlevin kaç uygulaması var? Uygulama elemanların türünü bilemediğinden, artık çok sayıda uygulama hariç tutulabilir: elemanlar birleştirilemez, listeye eklenemez veya filtrelenemez, vb. Kimlik (listede değişiklik yok), öğeleri bırakma veya listeyi tersine çevirme gibi şeylerle sınırlıyız. Bu işlevin yalnızca imzasına bağlı olarak akıl yürütmesi daha kolaydır.

Bunun dışında… Java'da yazım sisteminde her zaman hile yapabilirsiniz. Bu genel yöntemin uygulanması, instanceofkontroller ve / veya rastgele türlere çevirme gibi şeyler kullanabildiğinden , tür imzasına dayalı muhakememiz kolayca işe yaramaz hale getirilebilir. Fonksiyonu olabilir elementlerin türünü incelemek ve sonucuna dayanarak şey istediğiniz sayıda yapmak. Bu çalışma zamanı saldırılarına izin verilirse, parametreli yöntem imzaları bizim için çok daha az kullanışlı hale gelir.

Java'da tür silme yoksa (yani, tür bağımsız değişkenleri çalışma zamanında yeniden ifade edilmişse), bu, bu türden daha fazla akıl yürütmeyi bozan saçmalıklara izin verirdi . Yukarıdaki örnekte, uygulama, sadece listenin en az bir unsuru varsa, tip imzası tarafından belirlenen beklentileri ihlal edebilir; ancak Tsomutlaştırılmışsa, liste boş olsa bile bunu yapabilirdi. Biçimlendirilmiş türler, kodu anlamamızı engelleyen (zaten çok sayıda olan) olasılığı artıracaktır.

Tür silme, dili daha az "güçlü" hale getirir. Ancak bazı "güç" biçimleri aslında zararlıdır.


1
Görünüşe göre jeneriklerin Java geliştiricilerinin "anlayıp mantık yürütemeyecekleri" kadar karmaşık olduğunu ya da şans verilirse kendilerini ayaklarına vurmamalarına güvenilemeyeceğini savunuyorsunuz. İkincisi, Java'nın ethos (imzasız türler, vb.) İle uyumlu görünüyor, ancak geliştiricilere biraz küçümseyici görünüyor
Temel

1
@Temel Kendimi çok kötü ifade etmiş olmalıyım, çünkü kastettiğim bu değildi. Sorun, jeneriklerin karmaşık olması değil, döküm gibi şeyler ve instanceoftürlere göre kodun ne işe yaradığı hakkında akıl yürütme yeteneğimizi engellemesi. Java, tür bağımsız değişkenlerini yeniden ifade edecek olsaydı, bu sorunu daha da kötüleştirirdi. Türleri çalışma zamanında silmek, tür sistemini daha kullanışlı hale getirme etkisine sahiptir.
Lachlan

@lachlan bana çok mantıklı geldi ve normal bir okumanın Java geliştiricilerine herhangi bir hakaret olacağını düşünmüyorum.
Rob Grant

3

Bu doğrudan bir cevap değil (OP "faydaları nelerdir" diye sordu, "eksileri nelerdir" diye yanıtlıyorum)

C # tipi sistemle karşılaştırıldığında, Java tipi silme, iki dönem için gerçek bir sıkıntıdır

Bir arayüzü iki kez uygulayamazsınız

C # size hem uygulayabilirsiniz IEnumerable<T1>ve IEnumerable<T2>iki tür ortak bir atadan yok, özellikle güvenli (yani onların atası olan Object ).

Pratik örnek: Spring Framework'te ApplicationListener<? extends ApplicationEvent>birden çok kez uygulayamazsınız . TTest etmeniz gerekenlere göre farklı davranışlara ihtiyacınız varsainstanceof

Yeni T () yapamazsınız

(ve bunu yapmak için Class'a bir referansa ihtiyacınız var)

Başkalarının da belirttiği gibi, eşdeğerini yapmak new T()yalnızca yansıtma yoluyla yapılabilir, yalnızca bir örneğini çağırarak, kurucunun Class<T>gerektirdiği parametrelerden emin olarak. C #, new T() yalnızcaT parametresiz kurucuya kısıtlarsanız yapmanıza izin verir . Bu Tkısıtlamaya uymuyorsa, bir derleme hatası ortaya çıkar.

Java'da, genellikle aşağıdakilere benzer yöntemler yazmaya zorlanacaksınız.

public <T> T create(....params, Class<T> classOfT)
{

    ... whatever you do
    ... you will end up
    T = classOfT.newInstance();


    ... or more advanced reflection
    Constructor<T> parameterizedConstructorThatYouKnowAbout = classOfT.getConstructor(...,...);
}

Yukarıdaki koddaki dezavantajlar şunlardır:

  • Class.newInstance yalnızca parametresiz bir yapıcıyla çalışır. Hiçbiri yoksa, ReflectiveOperationExceptionçalışma zamanında atılır
  • Yansıtılmış kurucu, yukarıdaki gibi derleme zamanında sorunları vurgulamaz. Değişkenleri değiştirirseniz, yalnızca çalışma zamanında bilirsiniz

C # 'ın yazarı olsaydım, derleme zamanında doğrulanması kolay bir veya daha fazla yapıcı kısıtlaması belirtme yeteneğini ortaya koyardım (bu nedenle, örneğin string,stringparametreli bir kurucu gerektirebilirim ). Ama sonuncusu spekülasyon


2

Diğer yanıtların hiçbirinin dikkate almadığı bir nokta daha var: Çalışma zamanı yazmada gerçekten jeneriklere ihtiyacınız varsa, bunu kendiniz uygulayabilirsiniz :

public class GenericClass<T>
{
     private Class<T> targetClass;
     public GenericClass(Class<T> targetClass)
     {
          this.targetClass = targetClass;
     }

Bu sınıf, Java silme kullanmadıysa varsayılan olarak elde edilebilecek her şeyi yapabilir: yeni Ts ( Tkullanmayı beklediği modelle eşleşen bir kurucuya sahip olduğu varsayılarak ) veya Ts dizileri atayabilir belirli bir nesne bir nesne ise çalışma zamanında dinamik olarak testT ve buna bağlı olarak davranışı değiştirin, vb.

Örneğin:

     public T newT () { 
         try {
             return targetClass.newInstance(); 
         } catch(/* I forget which exceptions can be thrown here */) { ... }
     }

     private T value;
     /** @throws ClassCastException if object is not a T */
     public void setValueFromObject (Object object) {
         value = targetClass.cast(object);
     }
}

Olumsuz oylamanın nedenini açıklamak isteyen var mı? Bu, görebildiğim kadarıyla, Java'nın tür silme sisteminin sözde dezavantajının neden gerçek bir sınırlama olmadığına dair mükemmel bir açıklama. Peki sorun nedir?
Jules

Oy veriyorum. Çalışma zamanı tip kontrolünü desteklediğimden değil, ancak bu numara tuz madenlerinde kullanışlı olabilir.
techtangents

3
Java , tuz madenlerinin bir dilidir ve bu, çalışma zamanı türü bilgilerinin eksikliği göz önüne alındığında bunu basit bir gereklilik haline getirir. Umarım, tür silme işlemi Java'nın gelecekteki bir sürümünde geri alınır ve jenerikleri çok daha kullanışlı bir özellik yapar. Şu anda fikir birliği, itme / ağırlık oranlarının 1'in altında olduğu
yönünde

Peki, tabii ... TargetType'ınız jeneriklerin kendisini kullanmadığı sürece. Ancak bu oldukça sınırlayıcı görünüyor.
Temel

Genel türlerle de çalışır. Tek kısıtlama, bir örnek oluşturmak istiyorsanız, doğru argüman türlerine sahip bir kurucuya ihtiyacınız olmasıdır, ancak bildiğim diğer tüm diller aynı kısıtlamaya sahiptir, dolayısıyla sınırlamayı görmüyorum.
Jules

0

Aynı kod birden çok tür için kullanıldığından c ++ benzeri kod şişmesini önler; ancak, tür silme sanal gönderim gerektirirken c ++ - kod bloat yaklaşımı sanal olarak gönderilmeyen jenerikler yapabilir


3
Bu sanal gönderilerin çoğu, çalışma zamanında statik olanlara dönüştürülür, bu yüzden göründüğü kadar kötü değildir.
Piotr Kołaczkowski

1
çok doğru, çalışma zamanında bir derleyicinin kullanılabilirliği, java'nın c ++ 'ya göre birçok harika şey yapmasına (ve yüksek performans elde etmesine) izin verir.
büyücü


1
@jungle_mole evet, teşekkür ederim. çok az kişi, profil oluşturmadan sonra kodu tekrar derlemek için çalışma zamanında kullanılabilir bir derleyiciye sahip olmanın avantajını fark eder. (veya çöp toplama, çöp toplamanın çok büyük (çöp) olduğuna dair saf ve yanlış inançtan ziyade büyük-ah (çöp değil) veya çöp toplama küçük bir çaba olsa da, sıfır maliyete izin vererek telafi ediyor tahsis)). İnsanların topluluklarının inandığını körü körüne benimsediği ve ilk ilkelerden akıl yürütmeyi bıraktığı üzücü bir dünya.
necromancer

0

Cevapların çoğu, gerçek teknik ayrıntılardan çok programlama felsefesiyle ilgilidir.

Ve bu soru 5 yıldan daha eski olmasına rağmen, soru hala devam ediyor: Teknik açıdan neden tip silme isteniyor? Sonuç olarak, cevap oldukça basittir (daha yüksek bir seviyede): https://en.wikipedia.org/wiki/Type_erasure

Çalışma zamanında C ++ şablonları mevcut değildir. Derleyici, her çağrı için tam olarak optimize edilmiş bir sürüm yayınlar, yani yürütme tür bilgisine bağlı değildir. Ancak bir JIT aynı işlevin farklı sürümleriyle nasıl ilgilenir? Tek bir işleve sahip olmak daha iyi olmaz mıydı? JIT'in tüm farklı sürümlerini optimize etmek zorunda kalmasını istemezdim. Peki, peki ya tip güvenliği? Sanırım bu pencereden dışarı çıkmalı.

Ama bir saniye bekleyin: .NET bunu nasıl yapıyor? Yansıma! Bu şekilde, yalnızca bir işlevi optimize etmeleri ve ayrıca çalışma zamanı türü bilgilerini almaları gerekir. İşte bu yüzden .NET jenerikleri eskiden daha yavaştı (çok daha iyi hale gelmelerine rağmen). Bunun uygun olmadığını tartışmıyorum! Ancak pahalıdır ve kesinlikle gerekli olmadığında kullanılmamalıdır (dinamik olarak yazılmış dillerde pahalı kabul edilmez çünkü derleyici / yorumlayıcı yine de yansımaya dayanır).

Bu şekilde, tür silme ile genel programlama sıfıra yakındır (bazı çalışma zamanı kontrolleri / yayınlamaları hala gereklidir): https://docs.oracle.com/javase/tutorial/java/generics/erasure.html

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.