şükela:  tümü | bugün
  • ing. tip silimi. java'da generics ("genel amaçlılar" diye çevireyim) özelliğinin dayandığı temel budur. bir genel amaçlı tip için (orn: ahmet<t>) t tipine erişim olan her yerde oluşumunun kullandığı tipe göre tip dönüşümü (typecast) yaparak işler. mesela ahmet<integer> ve ahmet<string> için ahmet class'ı içinde çalışan kodlar (integer)member, (string)member olarak çalışır. bu da aslında tüm kodların ahmet<object> kıvamında bir sınıf üzerinden daimi tip dönüşümleriyle çalışmasına yol açar.

    c#'ta ise mis gibi ahmet<t> gibi bir kodda her ahmet<t> instance'ında yeni bir tip için jit yeni kod üretir. bu sayede ilk instantiation sırasında bir derleme zamanı kaybı yaşarsınız ama karşılığında genel çalışma zamanı boyunca süper performans artışı yaşarsınız. ayrıca bu sayede value type'ları da genel amaçlı tiplerle kullanmak mümkün olur. type erasure'da olduğu gibi "tip bilgisinin kaybolması" gibi dezavantajları da yoktur.
  • .net'te generics geriye uyumluluk sallanarak getirilmemiştir. genel amaçlı olmayan tipler aynen korunmuştur. haliyle .net 1.1 kodunu bugün .net 4.5'ta değişiklik yapmadan derlemek gayet mümkün (geriye uyumluluğu kıran değişiklikler var ama sayıları ve kapsamları çok ufak). lakin genel amaçlı kodun genel amaçlı olmayan (.net 1.1) interface'lerle tip dönüşümü uygulamadan bir arada çalışması (interoperability) mümkün değil. mesela arraylist alan bir .net 1.1 kaynak koduna dönüştürmeden list<t> paslayamazsınız. bence önemsiz ve bugüne kadar .net'te beni tökezletmemiş bir ayrıntı. microsoft'un beni düşünerek süper bir tercih yapmış olmasından memnunum.

    ayrıca:

    (bkz: project valhalla)
  • ayrıca resmi dökümanlarda da geriye uyumluluk için değil tam tersine eski kodun ileriye dönük uyumlu olması için tercih edildiği de (bkz: upward compatibility) açıkça belirtilmiş, bu açıdan .net'le aynı gerekçelerle bir tercih yaptıkları fakat onu da yanlış yaptıkları ortaya çıkıyor:

    https://www.jcp.org/en/jsr/detail?id=14 (section 2)
  • (bkz: .net vs java)

    kesin olarak java'nın tasarım yanlışlıkları nedeni ile uygulamak zorunda kaldığı çok kötü bir fikrin sonucudur. geriye doğru uyumla zerre ilgisi yoktur.

    (bkz: arkandayız reyiz)
  • adamlar generics'i geliştirirken interoperability hedeflememişler. "upward migration path olsun yeterli" demişler. "interoperability önemli" diye bir şey ağızlarından çıkmamış. şans eseri elde edilmiş olan interop imkanını bir mühendislik başarısı gibi göstermek insanları yanlış bilgilendirmek oluyor.

    reification da o hedefler çerçevesinde gayet süper iş görürmüş. yanlış karar vermişler. linkini de verdiğim üzere simdi bırak interop'u breaking change'lerle değiştirmeye çalışıyorlar. hala "o zaman o gerekli ve onemliydi ondan yapmışlar" demeyin.

    ne demiyorum: "interoperability önemsizdir" demiyorum.
    ne demiyorum: "benim şahsi tecrübem herkesi temsil eder" demiyorum.
    ne diyorum: "type erasure, java'nın mühendislik hedefleri çerçevesinde dahi reification'dan daha kötü, haliyle yanlış bir tercih olmuş. microsoft zar atıp yapmış olsa bile doğru tercih yapmış. teşekkürler microsoft".
  • java'da kullanilan generic type parameter'lar, function method signature'larindan silinir compile-time esnasinda, bunu gozlemlemek icin ornek bir programi javap'de -s parametresiyle decompile ederek gorebilirsiniz;

    import java.util.list;
    public class erasureexample<t> {
    public void method1(list param_m1) {}
    public void method2(list<t> param_m2_a, list<list<t>> parm_m2_b) {}
    }

    javap ciktisinda yukaridaki generic tip betimlemeleri yok olur, descriptor'lara dikkatlice bakarsaniz her sey raw type'a donusmustur;

    >javap -s erasureexample
    compiled from "erasureexample.java"
    public class erasureexample<t> {
    public erasureexample();
    descriptor: ()v

    public void method1(java.util.list);
    descriptor: (ljava/util/list;)v

    public void method2(java.util.list<t>, java.util.list<java.util.list<t>>);
    descriptor: (ljava/util/list;ljava/util/list;)v
    }
  • her ne kadar compile-time'da method signature'lardan generic tip parametreleri silinerak raw type'lara donusturulse de (bkz: object), run-time esnasinda (bkz: bytecode) type cast check'lerine rastlarsiniz (bkz: checkcast), bunu gozlemlemek icin de bytecode'a -c parametresiyle bakmaniz mumkundur. compile-time'da her sey raw type'a donusur ama bytecode'da string ya da herhangi bir obje icin checkcast'lar konur, ilginc.

    https://docs.oracle.com/…-6.html#jvms-6.5.checkcast
  • java da generic sınıfların compile edilmeden önce uygun sınıflara döndürülmesi olayıdır. yani aslında <t> diye bişey yok siliniyormuş. evet ben de yıkılmıştım ilk duyduğumda
  • bunun kotu bir yan etkisini soyle ozetleyebilirim. parametreleri generic listten olusan asagidaki iki overloaded method'u java compile etmeyecektir. method signature'lari farkli olmasina ragmen hata almamiz gariptir degil mi ;

    public void print(list<string> param) {}
    public void print(list<integer> param) {}

    halbuki ayri ayri integer ve string parametrelerinden olusan asagidaki iki overloaded methodu compile ederken sikinti yasamiyoruz;

    public void print(integer param) {}
    public void print(string param) {}

    buna sebep olan type erasure'dir, list<t> tipindeki parametrelerin generic t tipleri compile-time'da silinir ve raw type'lara yani java.util.list'e donusur. haliyle generic listelerden olusan overloaded method signature'larindan t silinince, ayni method signature'a sahip iki print methodumuz olmus olur, bu da compile error'e sebep olacaktir.