1 puan yazan GN⁺ 2024-08-04 | 1 yorum | WhatsApp'ta paylaş
  • Java, tiplere nullness marker ekleyerek Foo! ile null'ı reddeden, Foo? ile ise bilerek izin veren bir preview language feature hazırlıyor
  • İşaretsiz Foo, nullness'i unspecified olarak bırakıyor ve mevcut kodla uyumluluğu koruyor; nullness'i farklı tipler arasında dönüşüm uyarı veya çalışma zamanı denetimi içerebiliyor
  • null'ı reddeden alanlar ve diziler varsayılan değer olarak null kullanamadığı için, örnek alanları super(...) çağrısından önce kesin olarak atanmalı ve diziler için bileşen başlangıç değeri gerekli
  • null, Foo!'a daraltılırsa NullPointerException oluşuyor; dizi ve alan yazma yollarında ise kirlenmeyi önlemek için ArrayStoreException ve FieldStoreException kullanılıyor
  • Valhalla'nın value class flattening gibi optimizasyonları, null dışlamasını güvenilir kılan temeli sağlıyor; standart kütüphaneye uygulama veya mevcut kodu otomatik yeniden yorumlama şu anki hedefler arasında değil

Java tiplerinde nullness'i açıkça belirten preview özelliği

  • Java tiplerine nullness marker eklenerek tipin değer kümesine null'ın dahil olup olmadığı ifade ediliyor
  • Foo!, null-restricted tiptir ve değer kümesinden null'ı çıkarır
  • Foo?, nullable tiptir ve değer kümesine null'ı bilerek dahil eder
  • İşaretsiz Foo, nullness'i unspecified bırakır; null oluşabilir ama bunun kasıtlı olup olmadığı bilinmez
  • Bu özellik, derleme ve çalışma zamanında --enable-preview bayrağıyla etkinleştirilen bir preview feature'dır

Hedefler ve hedef dışı konular

  • Java referans tiplerinin null bekleyip beklemediğini ifade etmek ve nullness'i farklı tipler arasındaki dönüşümlerde uyarı ile denetim sağlamak
  • Mevcut Java koduyla uyumlu olmak ve kaynak ya da ikili uyumsuzluk oluşturmadan kademeli olarak devreye alınabilmek
  • null'ı reddeden tipteki değişkenlerin ilk okunmadan önce başlatılmasını zorunlu kılmak ve ayrı derlenmiş sınıflarda da çalışma zamanında null reddini uygulamak
  • Valhalla'nın value class flattening'i gibi çalışma zamanı optimizasyonlarının null kısıtlı tiplere güvenebilmesi için metadata ve bütünlük güvencesi sağlamak
  • Şu anda hedeflenmeyenler:
    • Mevcut kodu otomatik olarak yeniden yorumlamamak
    • Olası tüm null durumlarını derleme hatasına dönüştürmemek
    • int gibi primitive tiplere nullable biçim eklememek
    • Bu aşamada dil genişlemesini standart kütüphaneye uygulamamak

Neden gerekli

  • Java'da String değişkeni bir String nesne referansı ya da null tutabilir, ancak dil düzeyinde hangisinin amaçlandığını ifade etmenin yolu yoktur
  • Pek çok program null olmadığını varsayar, ancak bunu Javadoc sözleşmeleri ve uygulama kodunda tutarlı biçimde zorunlu kılmak ek çaba gerektirir
  • Bu beklenti bozulduğunda null değeri uygulama kodunun içine sızıp asıl hatadan oldukça uzakta bir noktada istisna üretebilir
  • Geliştirici, tipin bir parçası olarak null'ı reddetme veya kabul etme niyetini ifade ederse, derleme zamanı geri bildirimi ve çalışma zamanı denetimleri beklenmedik null'ları daha erken bulmaya yardımcı olur
  • Valhalla'da value class tipindeki değişkenler değerin flattened representation'ı ile optimize edilebilir; ancak null kodlaması için ek bit gerekirse bellek kullanımı artabilir veya depolama optimizasyonu yapılamayabilir
  • Amber'da pattern matching adayının nullness'i, switch için exhaustiveness değerlendirmesini etkileyebilir; tip deseninin nullness'i de null ile eşleşip eşleşmeyeceğini etkileyebilir

Nullness marker sözdizimi ve tip yapısı

  • Nullness, tipin ayrılmaz bir parçası sayılır; Foo? ile Foo, nullness'leri farklı olduğu için farklı tiplerdir
  • Hem dizi tipi hem de dizi bileşen tipi nullness marker taşıyabilir
    • Foo?[]!, dizinin kendisinin null-restricted, bileşenlerinin ise nullable Foo olduğu bir tiptir
    • Çok boyutlu dizilerde her köşeli parantez çiftinin ardından marker konabilir; geleneksel olarak soldan sağa, dıştan içe yorumlanır
  • Parametreli tipler ve tip argümanları da nullness marker taşıyabilir
    • Predicate!<Foo?>, null-restricted bir Predicate'tir ve tip argümanı nullable Foo'dur
  • Null kısıtlı ya da null izinli tipi ifade etmek için kaynakta ! veya ? açıkça bulunmalıdır
  • Gelecekte, bir sınıf ya da derleme birimindeki tüm tiplerin varsayılan olarak null-restricted yorumlanıp yalnızca ?'ın istisna olarak kullanılması değerlendirilebilir; ancak ayrıntılar ayrı bir çalışmadır

Alan ve dizi başlatma kuralları

  • Mevcut Java'da referans tipli alanların ve dizi bileşenlerinin varsayılan değeri null'dır, ancak bu değer null-restricted alanlar veya dizi bileşenleri için uygun değildir
  • Null-restricted alanlar ve diziler, okunmadan önce program tarafından her zaman başlatılmalıdır
  • Null-restricted örnek alanının initializer'ı yoksa, her constructor'da açık ya da örtük super(...) çağrısından önce definite assignment yapılmalıdır
    • Flexible Constructor Bodies JEP, constructor'ın başında gerekli başlatma kodunun yazılmasına izin verir
    • Bu early construction context içinde this'e başvurmak veya başlatılmamış alanları okuma riski taşıyan işlemler yasaktır
  • Null-restricted örnek alanında initializer varsa, her constructor başlangıcında super(...) çağrısından önce çalıştırılır
    • this(...) çağıran constructor, mevcut kurallarda olduğu gibi initializer çalıştırmayan özel durumdur
  • Null-restricted static alanlar, sınıfın tüm static initializer'ları ve başlatma blokları bittiğinde definite assignment almış olmalıdır
    • Başka bir sınıf, sınıf başlatması sırasında bu alanı okumaya çalışırsa çalışma zamanı denetimi erken okumayı saptar ve istisna fırlatır
  • Bileşen tipi null-restricted olan dizilerde, dizi oluşturma ifadesi her bileşen için başlangıç değeri sağlamalıdır
    • Dizi initializer'ı ile tüm değerler tek tek yazılabilir
    • Yeni bir kısaltılmış sözdizimi de mümkün, ancak sözdizimi henüz TBD

İfade nullness'i ve nullness dönüşümleri

  • Java derleyicisi tip denetimi sırasında her ifadenin nullness'ini belirler
  • Değişken başvurusunun nullness'i değişken bildiriminden, metot çağrısının nullness'i ise başvurulan metodun dönüş tipinden gelir
  • null literal'i nullable'dır
  • Diğer referans tipli ifadelerin çoğu null-restricted'dır
    • Buna literal'ler, string birleştirme, this, sınıf örneği oluşturma, dizi oluşturma, method reference ve lambda ifadeleri dahildir
  • Nullness dönüşümü; atama, çağrı ve cast bağlamlarında izinlidir
  • Genişletici nullness dönüşümleri şunları içerir:
    • Foo!Foo?
    • Foo! → unspecified Foo
    • Foo? → unspecified Foo
    • unspecified FooFoo?
  • Daraltıcı nullness dönüşümleri şunları içerir:
    • Foo?Foo!
    • unspecified FooFoo!
  • Daraltıcı nullness dönüşümleri, unboxing dönüşümüne benzer biçimde derleyici tarafından otomatik yapılır; ancak çalışma zamanında dinamik denetim yapılarak NullPointerException üretilebilir
  • null literal'ini doğrudan null-restricted tipe dönüştürme girişimi derleme zamanı hatasıdır

Çalışma zamanı denetimleri ve istisnalar

  • Çalışma zamanında null değeri, null-restricted tipe daraltıcı nullness dönüşümünden geçerse NullPointerException oluşur
  • Kaynak kodda açıkça görünmeyen daraltıcı nullness dönüşümleri de çalışma sırasında ortaya çıkabilir
  • Bileşen tipi null-restricted olan bir dizi, kaynak kodda daha az spesifik bir tip olarak ele alınsa bile normal dizi depolama denetiminde null değerini reddeder
    • Bu dönüşüm başarısızlığı ArrayStoreException üretir
  • Derleme zamanında null-restricted olmayan bir alan, daha sonra ayrı bir derlemeyle null-restricted olursa yeni field store check null depolamayı reddeder
    • Bu dönüşüm başarısızlığı FieldStoreException üretir
  • Override ilişkisindeki metot çağrılarında, üst metodun parametre çağrı tipine dönüşümün ardından overriding metodun parametre tipine dönüşüm gelebilir
  • Metot dönüş değeri de önce bildirilen metot dönüş tipine, ardından çağrı noktasının beklediği dönüş tipine dönüştürülebilir

Generics, tip argümanları ve overriding

  • Type variable kullanımlarına da nullness marker eklenebilir; T! null-restricted, T? ise nullable tiptir
  • Null-restricted ve nullable type variable tipleri, generic kod içinde belirli bir nullness'i ileri sürer
  • Tip argümanı olarak kullanılan tipler de nullness ifade edebilir; type variable type üzerindeki nullness marker, tip argümanında ileri sürülen nullness'in üzerine yazar
  • Generic API'nin erased implementasyonu içinde null kısıtlaması uygulanamaz
    • Ancak generic API sınırlarında ortaya çıkan normal örtük cast'ler, çalışma zamanında null-restricted tip argümanlarını uygular
  • Birlikte çalışabilirlik için tip argümanları içindeki nullness güçlü biçimde zorlanmaz
    • Predicate<String!>; Predicate<String> ya da Predicate<String?> tipine dönüştürülebilir
    • Bu tür unchecked nullness conversion işlemleri uyarı üretebilir
  • Dizi bileşen tipinin nullness'ini değiştirmek de unchecked nullness conversion olarak izinlidir; hangi koşullarda çalışma zamanı denetimi yapılacağı henüz TBD
  • Metot signature eşdeğerliği değerlendirilirken nullness göz ardı edilir
    • Parametre ve dönüş tiplerinin nullness'i uyuşmasa da bir metot diğerini override edebilir
    • Farklı API'ler nullness marker'ları bağımsız olarak benimserse bu tür uyuşmazlıklar yaygın olabilir
  • Nullness, metodun uygulanabilirliğini etkilemez ve tip argümanı çıkarımının başarısız olmasına yol açmaz; ancak generic metodun dönüş tipi için çıkarılan nullness'i etkileyebilir
    • Çıkarım algoritmasının ayrıntıları TBD

Derleyici uyarıları ve hatalar

  • Bir tipi null-restricted yapmak yeni derleme zamanı hataları doğurabilir
    • O tipteki alan veya diziler başlatılmamışsa
    • null literal'i o tipe dönüştürülmeye çalışılıyorsa
    • null literal'inin null-restricted tipteki ifadeyle karşılaştırılması da derleme zamanı hatası olabilir
  • Bunun dışındaki durumlarda nullness analizi yardımcı niteliktedir ve derleme zamanı hatası üretmez
  • javac, çalışma zamanı hatalarını önlemeye yardımcı olmak için uyarılar sağlar; IDE'ler ve diğer analiz araçları için de aynı yaklaşım önerilir
  • Olası uyarı nedenleri:
    • ? tipinden gelen durumlar dahil daraltıcı nullness dönüşümleri
    • ? tipli ifadelerin üye erişimi veya diğer null-hostile işlemlerde kullanılması
    • Tip argümanlarının nullness'inin bound ile tutarsız olması
    • Metot parametresi ya da dönüş nullness'inin override edilen metotla uyuşmaması
    • Tipin nullness'ini değiştiren unchecked conversion işlemleri

Class file, reflection ve yardımcı değişiklikler

  • Null marker kullanımının çoğu class dosyasında silinir; buna eşlik eden çalışma zamanı dönüşümleri ise doğrudan bytecode içinde ifade edilir
  • Signature özniteliğinin sözdizimi, tip içinde ! ve ? kullanımına izin verecek şekilde güncellenir
  • Nullness, metot ve alan descriptor'larında kodlanmaz
  • Alan kirlenmesini önlemek için yeni NullRestricted özniteliği, alanın null değere izin vermediğini belirtir
    • Bu alan aynı zamanda ACC_STRICT işaretini de taşımalıdır ve strict initialization uygulanmalıdır
    • Doğrulayıcı, constructor super(...) çağrısı yaptığında strict initialization gerektiren tüm örnek alanlarının atanmış olup olmadığını denetler
    • Alana yazma yönündeki her girişim null değerini kontrol eder ve bulunursa FieldStoreException fırlatır
  • Null-restricted dizi oluşturma, anewarray komutuyla desteklenmez; reflection API çağrısıyla yapılmalıdır
  • Foo!.class ya da Foo?.class literal'i yoktur; bunlara karşılık gelen bir java.lang.Class örneği de bulunmaz
  • Yeni RuntimeType API, dizi ve alan depolama denetimlerinde çalışma zamanında uygulanan tip kümesini tanımlar ve tüm sınıf ile arayüz tiplerinin null-restricted varyantlarını içerir
  • Field API, alanın RuntimeType bilgisini sorgulamayı destekler; bu değer getType sonucundan farklı olabilir
  • Array API, bileşen tipini RuntimeType ile ifade eden bir newInstance varyantını destekler
    • Bu varyant, dizi bileşeni için başlangıç değeri verilmesine de izin verir
    • Başlangıç değeri olmadan null-restricted dizi oluşturma girişimlerini reddeder
  • Geleneksel deserialization, null-restricted alanlar ve dizilerle uyumlu değildir; ayrı bir JEP, başlatılmamış null-restricted alan ve dizileri açığa çıkarmayan bir serialization mekanizması sağlayacaktır
  • javadoc tarafından üretilen belgeler nullness marker'larını içerir
  • java.lang.reflect.Type ve javax.lang.model API'leri, tip gösteriminde nullness'i kodlar

Alternatifler ve bağımlılıklar

  • Java ekosistemindeki çeşitli geliştirme araçları kendi derleme zamanı null izleme sistemlerini uyguladı; ancak Java dilini değiştirmedikleri için sözdizimi çoğunlukla annotation'larla sınırlı kaldı ve etkileyebildikleri davranış da derleme zamanı denetimleriyle sınırlı oldu
  • Diğer diller nullness'i tip sisteminde izler; birçok dil varsayılan olarak null-restricted'dır ve açık null denetimi olmadan null-restricted tipe atamayı hata sayar
  • Java'da bu özellik isteğe bağlı olmalı ve tek seferlik büyük bir geçiş gerektirmeden kademeli kullanılabilmelidir
  • Çalışma zamanı nullness zorlaması, açık denetimler veya Objects.requireNonNull çağrılarıyla da uygulanabilir
    • Ancak bunu tutarlı biçimde uygulamak zahmetlidir, ek belgelendirme gerektirir ve programın okunabilirliğini düşürür
    • Alan ve dizi gibi değişken depolama alanlarına doğrudan uygulanabilecek bir yöntem yoktur
  • Önkoşul, Flexible Constructor Bodies (Second Preview) özelliğidir
    • Constructor'ın super(...) çağrısından önce ifadeler çalıştırıp örnek alanlarına atama yapabilmesi, null-restricted alan başlatma gereksinimini mümkün kılar
  • Gelecek çalışmalar arasında şunlar bulunur:
  • Olası ek gelecekteki iyileştirmeler arasında standart API'nin bazı bölümlerine nullness marker uygulanması, bytecode'da daha kısa null check gösterimi, null-restricted metot parametreleri için daha güçlü düşük seviyeli zorlama ve belirli bağlamlardaki tüm tipleri örtük olarak null-restricted sayan dil mekanizmaları yer alır

1 yorum

 
GN⁺ 2024-08-04
Hacker News yorumları
  • Bu yaklaşımın birkaç yıl önce C#’ın benimsediği yöntemden farklı olması ilginç. C#’ta bir projede null kabul edilebilirliği açtığınızda, açıkça nullable olarak işaretlenmediği sürece tüm değişkenler non-null olarak bildirilir; bu öneride ise mevcut değişkenler fiilen nullable, açık nullable ya da açık non-nullable seçeneklerinden biri oluyor.
    Kotlin de bir JVM dili, ancak C# gibi açıkça belirtilmediğinde non-null kabul ediyor; sadece Kotlin’in geriye dönük uyumluluk yükü yok. lateinit var ile non-nullable bir tipi başka bir metotta başlatılana kadar boş bırakabiliyor ve başlatmadan önce erişilirse özel bir istisna fırlatan bir geçici çözüm de sunuyor.
    Neden üç seçenek koyduklarını merak ediyorum. Açıklama eklenmemiş değişkenleri nullable tutup, yalnızca açıklama eklenmiş değişkenleri açık non-null yapmak olmaz mıydı diye düşünüyorum. Hiçbir işaret olmasa da otomatik olarak nullable ise, ayrıca nullable bildirmek istemek için bir neden aklıma gelmiyor.
    C# yöntemini daha çok seviyorum, ama bu yöntemin avantajı, legacy kod tabanlarında null kabul edilebilirlik sorunlarının tamamını çözmeden kullanılabilmesi. Buna karşılık C# null kabul edilebilirlik sorunlarını hemen ortaya çıkarıyor; bu öneri ise şimdiye kadar olduğu gibi bunları saklı tutabiliyor.
    Ayrıca “bir metot, parametrelerinin ve dönüş değerinin null durumları uyuşmasa da başka bir metodu override edebilir” kısmı garip. Bir callback’i override/implement ederken asıl metot non-null dönüş belirtmişken null döndüren bir ayağa sıkma durumuna dönüşecek gibi görünüyor.

    • Şu an şirkette legacy bir C# kod tabanını nullable reference type’lara taşıyoruz; açık bir non-nullable işareti olsaydı, zaten gözden geçirilip açıklama eklenmiş kısımları hemen anlayabilmek gerçekten iyi olurdu.
      Zaman nedeniyle şu anda birkaç kritik nokta dışında yalnızca açıklamaları açma yolunu seçtik, ama bilinçli karar verdiğimiz yerleri hemen görebilmek için JetBrains’in NotNullAttribute ve CanBeNullAttribute değerlerini hâlâ işaret olarak tutuyoruz. İkincisi, nullable için açık işaret bulunduğundan kaldırılabilir; ancak birincisi C#’ın kendi özelliğiyle ad çakışması yaşıyor.
      Bu anlamda üç seçenek oldukça yerinde. Çünkü kod yüz binlerce satır olduğunda hızlı ve kolay geçiş yapmak zor.
      Diğer iç projelerde, dokunduğumuz kodun çevresine #nullable enable serpiştirerek null kabul edilebilirlik kapsamını kademeli genişletiyoruz. Yeni kodun nullable context içinde olması şartını da koyuyoruz. Bu da zaten açıklama eklenmiş kısımları belirtmek için fena değil, ancak çok daha küçük bir kod tabanı ve ekipte mümkün olan bir yöntem.
    • Kotlin’de de doğrudan tanımlayamasanız da null kabul edilebilirliği belirtilmemiş tipler var. Kotlin bunlara platform tipleri (platform types) diyor ve hata ile tanılarda String! gibi ünlem işaretiyle gösteriyor.
      “Platform tipi” terimi ve ünlem sembolü kafa karıştırıcı, ama bunun dışında Kotlin yaklaşımı oldukça iyi çalışıyor. Kotlin’de baştan beri null kabul edilebilirliği olduğu için programcılar platform tiplerini doğrudan belirleyemiyor; ancak JVM veya JavaScript gibi null kabul edilebilirliği belirsiz temel platformlarla uyumluluk için bunlar hâlâ gerekli.
      Bu yaklaşımda varsayılan değer hâlâ makul. Varsayılan olarak her zaman non-nullable olmalı; aksini düşünen biri Tony Hoare’dan hiçbir şey öğrenmemiş demektir. Aynı zamanda geriye dönük uyumluluk da korunuyor. Kotlin için bu kolay taraftaydı; Java ve C# ise mevcut kaynak kodla uyumluluğu da korumak zorunda.
      Ne Java yöntemi ne de C# yöntemi ideal. C# yöntemi, derleyici bayrağına göre kodun davranışını büyük ölçüde değiştiriyor; Java yöntemi ise varsayılanı en kötü seçenek haline getiriyor.
      Yine de C# tarafına daha yakınım. Çünkü “muhtemelen null olabilir” seçeneğini en kolay seçenek yaparsanız çoğu programcı varsayılan olarak onu seçecektir. Özellikle Java gibi kurumsal dostu bir dilde bu daha da olası. Linter’lar ve derleyici uyarıları uzun vadede yardımcı olur, ancak Java kodunun çoğunda null kabul edilebilirliğinin düzgün açıklanması yıllar alacak gibi görünüyor. C# kullanıcıları kısa vadede daha çok acı çekecek, ama açık null kabul edilebilirliği hedefine çok daha hızlı ulaşma olasılıkları yüksek.
      https://kotlinlang.org/docs/java-interop.html#null-safety-an...
      https://www.infoq.com/presentations/Null-References-The-Bill...
    • Garip olduğuna katılıyorum. Beklediğim yöntem, kaynak kod düzeyinde T?’nin nullable, T!’nin non-nullable anlamına gelmesi ve yeni derlenen kaynaklarda normal T varsayılanının kaynak dosyası bazında, package-info dosyası bazında veya derleyici anahtarıyla global olarak belirlenen pragma benzeri bir bildirim ile ayarlanmasıydı.
      Daha sonraki bir LTS Java sürümünde global varsayılan değiştirilebilirdi. Böylece proje geçişi kolaylaşır, pragma otomatik olarak eklenip/güncellenebilir ve gerekirse eski varsayılan da korunabilirdi.
      Ayrıca mevcut JSR-305 @Nonnull açıklaması, sınıf dosyalarında non-nullable tip görünümlerini ifade etme biçimi olarak kullanılsaydı, eski JDK’larla çift yönlü uyumluluk da sağlanabilirdi.
    • Son kısımda “programcının açık ! sembolünü yazmasına gerek kalmadan, belirli bir bağlamdaki tüm tiplerin örtük olarak null kısıtlı olduğunu dilin ifade etmesini sağlayan bir mekanizma sunma” diye bir bölüm var.
      Derleyici bayrağı ya da modül etiketi düzeyinde bir şey bile yeterli olabilir.
    • Nedeni, Java’nın diğer dillere kıyasla çok daha fazla önemsediği kod geriye dönük uyumluluğu olsa gerek.
      Yine de ayrıca belirtilmediğinde otomatik olarak non-nullable varsayan bir derleyici bayrağının geleceğini düşünüyorum.
  • İyi görünüyor. Sonunda dil düzeyinde binlerce gereksiz istisnayı ve null kontrolünü ortadan kaldırmanın bir yolu oluyor. Ancak null olup olmadığını daraltan otomatik dönüşüm yanlış hissettiriyor
    Teklifteki örneklerde String? id(String! arg) { return arg; }, String s = null;, Object! o1 = s; // NPE, Object o2 = id(s); // NPE, Object o3 = (String!) s; // NPE için en azından ilk iki durumun derleme hatası olması gerekmez mi diye düşünüyorum
    Sonuncusu açıkça belirtildiği için muğlak, ama bence if (s != null) içinde derleyicinin etkin türü String! olarak bilip String! ss = s; ifadesine izin vermesi daha iyi olurdu. O zaman hata ihtimali olmaz

    • Sektörde Java kullanmış biri olarak, dinamik kontrollerin yalnızca açıkça istendiğinde yapılması, geri kalan her şeyin statik olarak ele alınması daha iyi. Bean Validation, bir nesne geçici olarak hatalı olabilse bile açıkça doğrulama yapıldığı anda ya da framework benim koduma girmeden önce doğruladığı anda geçerli olduğu için iyi çalışıyor
      Aslında son durumdaki cast yerine Objects.requireNonNull(s) kullanmayı daha açık olduğu için tercih ederim. Yine de açık denetimi atlayıp yalnızca optimizasyon yüzünden engellenen durumları hariç tutan Objects.unsafeForceNonNull(s) gibi bir şey de olsa iyi olurdu. unsafe bir metot olursa, karmaşık statik analiz eklemeden doğrudan requireNonNull uygulanabilir
    • “Ortaya çıkabilecek tüm null değerleri programın açıkça işlemesini zorunlu kılmak hedef değildir; işlenmemiş null değerler derleme zamanında uyarı olabilir ama hata değildir” deniyor
      Ne yazık ki bu yalnızca çalışma zamanında kontrol edilecek
    • Birinci ya da ikinci örnek derleme hatası olursa, bu tüm kütüphane kullanım noktalarına anotasyon eklemek gerektiği anlamına gelir. İlgili kütüphane null türlere geçene kadar, ya da hiç geçmezse, neredeyse her satır cast ile dolacak. Mantıklı değil
      Örneğin standart kütüphane en azından bir süre null türlere geçmeyeceğini açıkça belirtiyor
    • Sorunun özü API’ye null sokmaksa, bunun bir dil hatası olup olmadığından emin değilim. Bunun gereksiz uzun olduğunu ve toparlamak gerektiğini anlıyorum, ama sonuçta sorun böyle kod yazan geliştiricilerde değil mi diye düşünüyorum
    • İkincisi derleme hatası olmazsa legacy kod non-null argüman alan fonksiyonları çağırabilir, ama bunun mutlaka iyi olup olmadığını bilmiyorum. Gerçekten kullanmadan karar vermek zor
  • Paket düzeyinde ya da en azından dosya düzeyinde tüm değişkenleri varsayılan olarak non-null işaretlemenin bir yolu kesinlikle gerekli görünüyor. Aksi halde güvenlik için neredeyse tüm değişkenlerde T! sözdizimini kullanma yönünde güçlü bir eğilim olur ve bu da çok fazla gürültü yaratır

    • “Gelecekte olası iyileştirmeler” altında “programcının açık ! işareti kullanmasına gerek kalmadan belirli bir bağlamdaki tüm türlerin örtük olarak null ile sınırlandırıldığını dilin beyan etmesini sağlayan bir mekanizma sunmak” yer alıyor
    • O kadar kötü olmayabilir. Bizim projemizde, sahip olduğumuz Java kodundaki tüm değişkenlerin null olmadığına dair zaten bir standart var. Nullable değişken gerekiyorsa @Null ile anotasyon eklemek gerekiyor
      Sorun yalnızca kütüphanelerle etkileşilen kod sınırlarında çıkıyor. Bu yeni sözdizimi de benzer olacak gibi
    • Agresif bir linter, işaretsiz türleri non-null kabul edip yalnızca gereken yerlerde null’a izin verilebilirlik işareti isteyebilir gibi
  • “Şimdilik dil iyileştirmelerini standart kütüphaneye uygulamak hedef değil” kısmı üzücü
    Mecburen PHP kullanmış biri olarak, veriler hakkında önceden garanti altına aldığın özellikleri devasa standart kütüphaneyle her etkileşimde soyup tekrar kurmak zahmetli
    Java’nın da bu ifade gücünü standart kütüphaneye daha aktif biçimde koyup birinci sınıf vatandaş yapması gerekiyor

    • Java’nın en büyük sorunlarından biri, kademeli olarak iyileştikçe yeni ve biraz iyileştirilmiş kodun bir sonraki kademeli özellikte tekrar legacy kod hâline gelmesi. Optional kullanan legacy kod, açık nullable/non-nullable önerisi için yük oluyor. Record türleri de varsayılan olarak non-nullable olabilirdi diye düşünüyorum
    • “Şimdilik” ifadesini “asla yapmayacağız” diye okuyorsun gibi, ama gerçekte bu geçişin kendisi devasa bir iş olduğu için ayrı ele almak istemelerine daha yakın
      Ayrıca iki aşamaya bölmek, bu özelliği preview özellik olarak daha kolay yayımlayıp geri bildirim aldıktan sonra tasarımı kesinleştirmeyi sağlar. Hepsini tek seferde yapmaya çalışırsan özelliği gerçekten yineleyerek iyileştirme alanı neredeyse kalmaz
    • Anahtar ifade “şimdilik”. Özellik yerleştiğinde bunun hedef olacağını düşünüyorum
    • Mecburen mi; modern PHP gayet konforlu
  • Bu özelliğin Java’ya gelmesini isterim. T? gibi dil düzeyinde açık seçilebilirlik, Kotlin ve TypeScript’te geliştiricilerin yaşam kalitesini ciddi biçimde artırdı. Java’da NullAway gibi araçlar var ama zahmetli
    Dil düzeyi desteğin Optional/Maybeden çok daha iyi olduğunu düşünüyorum. Çünkü kodu map/flatMap rayına oturtmak yerine gerçek mantığa odaklanmayı sağlıyor
    https://github.com/uber/NullAway

    • 30 yılı aşan kaynak uyumluluğunu bozmayı mı öneriyorsun? Bunu neden yapmak gerekir ki
      Sadece başka bir JVM dili kullanılsa olmaz mı
  • Site şu anda kapalı olduğu için arşiv bağlantısını bırakıyorum: https://web.archive.org/web/20240802081039/https://bugs.open...

    • Herkesin sevgilisi “jira”ya geçmelerine şaşırmadım
  • “Programın oluşabilecek tüm null değerleri açıkça işlemesini zorunlu kılmak hedef değil; işlenmemiş null değerleri derleme sırasında uyarı olabilir ama hata değildir” demek kötü bir karar
    Java zaten büyük ölçüde statik tipli bir dil; neden bir dinamik davranış daha ekleniyor anlamıyorum. Umarım bu uyarıları hataya yükseltmenin kolay bir yolu olur

    • Bunu yapamazlar. Yaparlarsa mevcut tüm Java programları bozulur. Zorunlu kılınırsa her programın her yerdeki null dönüşleri işleyecek şekilde yeniden yazılması gerekir. Bu ek özellikle zorunlu null işleme yalnızca yeni tiplerle ilgili işlemlere uygulanabiliyor; bu yüzden hiçbir şey bozulmuyor
      Her durumda null/nil işlemeyi tip sisteminin zorunlu kıldığı diller elbette çok daha iyi. Ama mevcut Java böyle bir dil değil. Yine de bu büyük bir iyileştirme olacak
  • Bu dersleri çok geç öğreniyor olmamız üzücü. Varsayılan olarak non-nullable, varsayılan olarak immutable, varsayılan olarak en dar kapsam olmalı
    Yeni tasarımlarda “güvenli yola düşürmek” yerine fazlasıyla sık şekilde anlık kullanım kolaylığı tercih ediliyor. Güvenli varsayılanlar çok daha özenli tasarım ve kullanıcı deneyimi gerektirir; ama sonuçta neredeyse her dilde, platformda ve teknolojide bir sürü ayağa sıkma tuzağı oluşuyor. İnşaat ve elektrik mühendisliğinde yönetmelikler var; yazılım ise yaklaşık her 30 yılda bir yeni dil ve teknolojilerde aynı dersleri yeniden öğreniyor

    • Ne yazık ki Java hâlâ varsayılan non-nullable kuralını öğrenmemiş gibi görünüyor. Bu öneri iki yeni tip getiriyor ama varsayılan, anotasyonsuz tipe nullable mı diye sorulduğunda hâlâ “eh, belli değil” yanıtını veriyor
    • Üzücü olan, Java’nın böyle şeyleri geç öğrenmesi. “Biz” ve “Java” aynı şey değil
      Java, mikropları öldürmek için suyu kaynatmak gerektiğini öğrenen üçüncü dünya köyü gibi
  • Facebook’ta yaptığım işlerin çoğu Hack kullanmaktı. Null olup olmama durumu Hack tip sisteminin temel bir unsuru ve gerçekten çok sayıda gereksiz hatayı çözüyor
    Elbette bu, beklenmedik bir null değerini hiç alamayacağınız anlamına gelmiyor. Bu özellik de dile sonradan eklendiği için PHP köklerini yansıtan legacy mixed tipi hâlâ çok fazlaydı; bu da fiilen her şey olabilir demekti
    Önce nullable dizilerin ne olacağını merak ediyorum. String![] örneği nesnenin null olabildiği durumu gösteriyor ama dizinin kendisi ne olacak? Java’da String labels[] = null; tamamen geçerli. O zaman String![]! labels; gibi mi bildirmek gerekir?
    Hack’te vec $foo, hem foo’nun hem de elemanların null olmadığı anlamına gelir; ?vec $foo ise elemanların non-null ama foo’nun nullable olduğu anlamına gelir. Pratikte null dizi kullanmak için neredeyse hiç neden yok, bu yüzden varsayılan null olamaz olmalı. Ancak Java’da tüm legacy kodun null olasılığını varsayması gibi bir sorun var
    Önerideki Object! o1 = s, Object o2 = id(s), Object o3 = (String!) s örneklerinde 2 ve 3’ün derleme hatası olması gerekmez mi diye düşünüyorum
    Son olarak Java’nın cast’inden çok Hack’in as zorlama operatörünü seviyorum. Örneğin foo($b) derleme hatası verir; $b as A, değer null ise runtime hatası verir; $a as ?B ise B ise cast eder, değilse null döndürür
    Sonuçta soru, bunun Java SDK üzerine uygulanıp uygulanamayacağı ve legacy kodda nasıl görüneceği oluyor
    https://docs.hhvm.com/hack/types/nullable-types

    • Muhtemelen sadece String![]? labels = null; olur
  • Kotlin’in iyi yanları artık Java’ya da giriyor gibi
    Yine de Lombok gibi şeylerle uğraşmak zorunda kalmadığım Kotlin’de çalışmaya devam etmek isterim. Java record’ları güzel gerçi

    • Yine de Java programcıları eski deyimleri kullanmayı sürdürecek ve eski kod tabanlarına bağlı kalacaklar. Bunların yaygın kullanıma girmesi uzun süreceği için Kotlin programcılarının endişelenmesine gerek yok
    • Java’nın başka dillerden ilham alma konusunda uzun bir geçmişi var. Geriye dönük uyumluluğu büyük ölçüde korurken oldukça iyi bir hızda gelişmeye devam ettiğini görmek güzel