Dart Null Safety Nedir? Ne işe yarar?

Zeki ÇIPLAK
Flutter Türkiye
Published in
6 min readMay 26, 2021

--

1. Giriş

Dart 2.9 versiyonu ile birlikte büyük bir değişikliğe imza attı. Null Safety, (Null Güvenliği) birçok kod probleminden kaçınmamıza ve kod performansımızı iyileştirmemize katkıda bulunuyor. Bu yazıda sizlere, -en basit haliyle- yapılan değişikliğin ne olduğundan bahsedeceğim ve bu yeniliğin gerek eski kodlarınıza, gerekse gelecekte yazacağınız kodlara nasıl uygulanabileceğini göstermiş olacağım.

2. Dart’ın Veri Türleri Sistemi

Halihazırda Dart içerisindeki tür sistemi (Type System), birçok hatalı kodlamanın önüne geçebilmektedir. Aşağıdaki kodda gördüğünüz gibi, int bir değişkene (yil), String bir değer ataması yaptığımızda, kodun derlenmediğini ve hatanın düzeltilmesi gerektiği ile ilgili bir hata mesajı geldiğini görürüz.

Tür sistemi, böylece daha güvenli programlar yazmamıza yardımcı olur. Birçok hatayı derlenme zamanında (Compiler Time) tespit edebilmemizi ve düzeltebilmemizi sağlar. Çünkü bildiğiniz gibi çalışma zamanı (Run Time), kullanıcı tarafından kodun çalıştırıldığı zamandır. Bu açıdan yazdığımız programda meydana gelebilecek tüm olası hataların, kod daha çalışmadan önce derlenme zamanında tespit edilebilmesi daha önemlidir.

Aşağıdaki örnekte ise, yazdığımız fonksiyonun sonucu, tür sisteminin güvenliğinden dolayı mutlaka int değeri döndürecektir. Fakat bu güvenlik olmasına rağmen, fonksiyondaki “sayi” değerinin null girilmesi durumunda hata meydana gelir. Çünkü null değerinin karesini almak anlamsızdır.

Fakat bu hata, eskiden (yani Null Safety yokken) derlenme zamanı meydana gelmez ve kodumuz bir hata yokmuş gibi derlenirdi. Kullanıcı, fonksiyon argümentine null bir değer girdiğinde hata meydana gelirdi. Eskiden bu sorunu aşabilmek için aşağıdaki gibi bir çözüme gidilirdi.

Fakat bu, hem daha fazla kod yazımına hem de performansın azalmasına yol açardı. Hemen hemen her değişken için böyle bir null kontrolü yapmak kodumuzu daha gürültülü hale getiriyordu.

3. Null Safety nasıl bir değişiklik getiriyor?

Null Safety’nin gelmesiyle birlikte, tüm değişkenler varsayılan (default) olarak, non-nullable (null değer alamaz) şeklinde kabul edildiği için, artık bu tip kontroller yapmak zorunda değiliz. Artık bir değişkene null değerini atadığımızda, daha kodu çalıştırmadan önce, Null Safety’den dolayı bir uyarı alacağız. Bu mesaj, bize ilgili değişkenin değerinin null olmaması gerektiğini belirtecektir.

Kendi makinenizde büyük ihtimalle son versiyon veya 2.9 sonrası bir versiyon Dart yüklü olacağı için Null Safety aktif olacaktır. Null Safety yokken, bu kodun nasıl bir sonuç vereceğini görebilmek için DartPad.dev adresine girip, alt kısımdan Null Safety ayarını kapatın. Kodun derlenmede hiçbir sorun çıkarmadığını ve RUN tuşuna bastığınızda hata meydana getirdiğini göreceksiniz.

Null Safety açıkken aynı kodu denediğinizde, kodu daha çalıştırmadan önce (yani derlenme zamanında) koddaki hatayı tespit etmiş olacaktır.

İşte bu açıdan Null Safety hem kod performansı hem de hataların kontrolü açısından önemli bir değişiklik olarak karşımıza geliyor. Peki değişkenlerimiz null değer almak zorunda ise, Null Safety de bunu engelliyorsa, bu durumda ne yapacağız? Tabii ki bunun da çözümü var.

4. Null değeri atayabilmek

Eğer oluşturduğumuz bir değişkenin null değerler de alabilmesini istiyorsak, verinin türünü belirten int, String gibi kelimelerden sonra ? kullanabiliriz. Böylece o değişkenin null değer alabileceğini de belirtmiş oluruz. Aşağıdaki kodu çalıştırdığımızda, word değişkeni null değer alabilmektedir.

Eğer String ifadesinin yanındaki ? karakterini kaldırırsanız, Null Safety aktif olan (yani Dart 2.9 ve sonrası yüklü olan makinelerde) word değişkeninin null değer alamayacağı ile ilgili bir uyarı çıkaracak ve kod derlenmeyecektir.

5. Generics ifadeler için Null Safety

Bildiğiniz gibi, dartta bir liste oluşturmak istediğimizde, listenin elemanlarının türlerini de Generics adı verilen bir yapıda sunabiliyorduk. Örneğin, List<String> liste = ["abc","def"]; dediğimizde, String elemanlardan oluşan bir liste oluşturmuş oluyorduk. Null Safety ile birlikte, artık bu ifadeler de non-nullable (yani null değer alamaz) hale geldiler.

Bu yüzden, null değer alabilmeleri için yine yukarıda kullandığımız gibi, ? karakterini kullanacağız. Aşağıdaki örneklerde, ? kullanılmadığında meydana gelen hatalar ile ? kullanılarak, nasıl null değerler verilebileceği gösterilmiştir.

Gördüğünüz gibi Null Safety, null bir liste oluşturmaya ve listeye null değerli bir eleman eklenmesine izin vermiyor. Kodu aşağıdaki gibi düzenleyerek, hataların kalkmasını ve listelerin null değer alabilmelerini sağlayabiliriz.

? karakterinin farklı yerlerde kullanıldığına dikkat edelim. Null elemanı olan bir liste oluşturmak için, ilgili veri türünün kelimesinden sonra, (yani bu örnekte String'ten sonra) ? karakterini kullanabiliriz. Eğer tamamen değeri null olan bir liste oluşturmak istiyorsak, Generics'ten sonra ? karakterini kullanabiliriz.

6. Koşula bağlı ifadeler için Null Safety kullanımı

Aşağıdaki örneği incelediğimizde, text değişkeninin kesinlikle null değer alamayacağını görürüz. Bu yüzden Null Safety açısından dikkat edilmesi gereken herhangi bir durum yoktur.

Fakat kodu aşağıdaki şekilde değiştirirsek, text değişkeninin null değer alabilme olasılığı doğar. Aşağıdaki kodda bu olasılık, tabii ki %100'dür ama biz null değer alabilme olasılığı olan bir değişkenimiz olduğunu varsayalım. Eğer text değişkeni, null olursa, text’in karakter sayısını veren text.length ifadesi anlamsız olacak ve hata meydana getirecektir.

Bu yüzden yine ? karakterimizi ilgili yerlerde kullanarak, text değişkeninin öncelikle null değer alabileceğini belirtmiş oluyoruz. Ardından, text.length ifadesini text?.length olarak değiştiriyoruz. Sonuç olarak bu değişiklikle, eğer text değişkeni null ise; tüm ifadenin null çıkmasını, null değilse; length'ten gelen değeri döndürmesini ve yukarıda meydana gelen hataları da önlemesini sağlamış oluyoruz.

Bununla ilgili farklı bir örnek daha gerçekleştirelim. Aşağıdaki kodda karakterSayisi(…); adlı bir fonksiyon tanımlanmıştır. Fonksiyon str isimli bir argüment almaktadır. Eğer str hiçbir şekilde null olmazsa, Null Safety açısından herhangi bir hata meydana gelmez.

Fakat str bir şekilde aşağıdaki gibi null değer alırsa, Null Safety devreye girer ve derlenme zamanı hata meydana gelir.

Eğer ilgili fonksiyon argümanının null değer alabilme olasılığı varsa, kodu Null Safety’e göre aşağıdaki gibi düzenleyebiliriz.

Dikkat ederseniz, burada diğer örnekten farklı olarak, fonksiyonun da null değer döndürebilme olasılığı olduğu için, int kelimesinden sonra da ? gelmiştir.

7. late kelimesinin kullanımı

Null Safety ile birlikte, Sınıf içerisinde tanımladığımız değişkenler de null yapılamaz hale gelmiştir. Aşağıdaki örnekte gördüğünüz gibi, Yemek sınıfında oluşturulmuş olan, String bir _tanim değişkeni hataya sebep olmaktadır.

Çünkü ilk değer olarak null değerini almaktadır. Bu durumu çözmenin bir yolu, ona null haricinde ilk bir değer atamaktır. Örneğin ilgili satırı, String _tanim = ""; şeklinde değiştirirsek, hata ortadan kalkacaktır. Bunu kendiniz deneyerek görebilirsiniz. Ancak bu geçici bir çözümdür ve tercih edilebilecek bir çözüm değildir. late kelimesini kullanmak ise daha yerinde bir karar olacaktır. late kelimesi ile dart sistemine, daha sonra bu değişkene bir değer atanacağını söylemiş oluyoruz. Bu şekilde herhangi bir hata da meydana gelmemiş oluyor.

Sınıf içerisinde final kelimesi ile değişken oluşturulduğunda, onun bir değer ile başlatılması (yani initialize işlemine tabi tutulması) gerekir. Üstteki sınıf örneğinde de, _tanim değişkenini alttaki resimde olduğu gibi, final kelimesi ile oluşturursak, yine bir hata ile karşılaşırız. Çünkü Yemek sınıfının yapıcı metodunda (yani constructor’ında) _tanim değişkenine herhangi bir değer atanmamıştır.

late final kullanımı ile oluşturduğumuz değişkenin hemen başlatma (initialize) işlemine tabi tutulmamasını ve o işlemin geciktirilmesini sağlamış oluyoruz. Aksi durumda, bir sınıfın yapıcı metodu çalıştığı an, final ile oluşturulan değişkenlerin değerlerinin girilmesi gerekir.

Böylece late final kullanarak, yukarıdaki örnekte oluşturulan _tanim değişkeninin değerinin atanması işlemi, main(…) fonksiyonunda, yemek.tanim = "Pilav Üstü Döner!"; satırı çalıştırılana kadar geciktirilmiş oluyor.

En temel hatlarıyla Null Safety kavramının ayrıntılarına değindim. Null Safety hakkında daha fazla bilgi edinmek için aşağıda verdiğim sayfaları ziyaret edebilirsiniz.

* https://dart.dev/null-safety/understanding-null-safety

* https://dart.dev/codelabs/null-safety

İyi çalışmalar dilerim.

--

--