Kotlin Types
Teknik konular hakkında Türkçe yazmak gerçekten çok zor. Bir çok kelimenin Türkçe karşılığını bulmakta zorlanıyorum. Yarı Türkçe yarı İngilizce yazmak hiç hoşuma gitmese de aklımdakileri bir an önce yazıya döküp paylaşmak için şimdilik çok fazla kafaya takmadan yazıyorum. Kimse kusura bakmasın lütfen.
Bir önceki yazımda Kotlin’in statik ‘type’ sistemli ve güvenli bir programlama dili olduğunu söylemiştim. Bu yazıda, ne demek istediğimi daha detaylı bir şekilde açıklamaya çalışacağım.
kotlin.Any ve Sınıf Hiyerarşisi
Kotlin’de class hiyerarşinin en tepesinde Any vardır. Hiçbir sınıftan türemeyen (super class’ı olmayan) bir sınıf oluşturursanız bu sınıfın super class’ı otomatik olarak Any olur. Bire bir aynısı olmasa da Any‘yi java’daki Object sınıfı olarak düşünebiliriz.
Şekildeki gibi bir sınıf hiyerarşisini aşağıdaki Kotlin sınıfları ile oluşturabiliriz.
ImageView ve TextView sınıflarını View sınıfından türetebilmek için View sınıfını open class olarak tanımlamamız gerekir çünkü Kotlin’de tüm sınıflar default olarak final‘dır. Aynı Java’da olduğu gibi Kotlin type sistemi de super-type/sub-type ilişkisini kontrol eder. Super-type bir değişkene sub-type bir değer atanabilir fakat bunun tersi mümkün değildir.
kotlin.Unit
Kotlin expression-oriented bir programlama dili oldugu için her statement bir değer döndürmek zorundadır. Örneğin if ve when birer expression’dır.
Kotlin bu yönüyle Java’dan ayrılır, functional programlama dillerine yakınlaşır. If statement’ların java’da bir değer döndürmediklerini zaten biliyoruz. Yukarıdaki Kotlin if statement örneğini Java’da yazmaya kalkarsak derleyici aşağıdaki gibi bir hata verecektir.
Java’daki void ‘un karşılığı Kotlin’de Unit‘tir. Geriye birşey döndürme ihtiyacı olmayan fonksiyonların (sadece side effect’i olan fonksiyonlar) return tipi Unit olur.
Fonksiyonları tanımlarken Unit return tipini yazmak zorunda değiliz. Yukarıdaki printMessage fonksiyonunu Unit kullanmadan da yazabiliriz.
kotlin.Nothing
Kotlin standart library içerisinde Nothing diye de bir sınıf var. Bu özel sınıf tüm sınıf hiyerarşinin en altında yer alıyor. Eğer bir fonksiyon bir değer üretmiyorsa (sonsuz bir döngüyse ya da exception throw ediyorsa) return tipi olarak Nothing kullanılabilir. Bu sayede IDE’ler ya da derleyiciler Nothing dönen fonsiyonlardan sonra çalışacak kodlar için unreachable code uyarısı yapabilirler.
Kotlin’de Primitive Tipler Yok
Kotlin’de Java’daki int, long, float gibi primitive tipler yoktur. Herşey metodunu çağırabileceğimiz bir object’tir. Java’daki primitive tip olan int‘e karşılık Kotlin’de Int vardır ve Int super-type’ı Any olan bir sınıftır. Primitive tiplerin olmamasi memory kulanimi açısından problem olabilir diye endişelenmeye gerek yok çünkü Kotlin Compiler, Int (ve diğer built-in tipler Long, Float, Double, Byte …) için gerekli optimizasyonunu yapmaktadır. Örneğin aşağıdaki kotlin ve java kodları derlendiğinde aynı byte code oluşur.
Elveda NullPointerException
Kotlin’in güvenli bir programalama dili olmasını sağlayan bir diğer özelliği de tiplerin “non null” ya da “nullable” olarak tanımlanabilmesidir. Örneğin Int ve Int? farklı tiplerdir fakat Int‘i Int?‘ın sub-type’ı olarak düşünebiliriz.
Yukaridaki View-TextView-ImageView class hiyerarşisini nullable tipleri de hesaba katarsak aşağıdaki gibi çizebiliriz.
Nullable ve non-null tipler, type system’e dahil olduğu için Kotlin derleyicisinin NULL güvenliğini (null safety) sağlamak için ekstra bir şey yapmasına gerek kalmıyor.
Production ortamında oluşan Exception’lar için bir istatistik hazırlamışlar ve bu istatistiğe göre en fazla karşılaşılan exception sizin de tahmin edebileceğiniz gibi meşhur(!) NullPointerException çıkmış. Bu bilgiye nasıl ulaştıklarını sorgulamadım çünkü yıllardır benim de karşıma hata olarak çoğunlukla NPE çıktı. NPE bir programcı hatası olduğu için Kotlin derleyicisini tasarlarken programcıların bu hataya tekrar tekrar düşmemeleri için nullable ve non null tipleri birbirinden ayırmışlar.
Nullable değişkenlerin metodlarına ve property’lerine güvenli bir şekilde (NPE’siz) erişmek için safe call operator ‘?.’) kullanabiliriz.
Güvenli erişimler zincir halinde de kullanılabilir. Örneğin:
Yukaridaki örnekte:
- textLength değişkeninin “inferred” tipi Int?‘dir.
- tv değişkeni null referans içeriyorsa getText() metodu çağırılmaz ve textLength null olur.
- tv null değilse ve getText() metodu null dışında bir değer dönerse textLength‘e Int tipinde bir değer atanır.
textLength değişkeninin hiçbir şekilde null olmasını istemiyorsak Elvis Operator ‘?:’ kullanabiliriz.
Yukarıdakı örnekte nonNullTextLength değişkeninin inferred tipi Int (non null)’tir. Elvis operatörü solundaki expression (tv?.getText()?.length) değeri null’dan farklıysa solundaki yoksa sağındaki expression değerini döner.
Peki Kotlin’de hiç mi NullPointerException olmaz? İstersek olur. NPE’siz yapamam diyenler için !! operatörü var. Aşağıdaki örnek çalıştırılırsa kotlin.KotlinNullPointerException oluşur.
NPE ile karşılaşmanın başka yolları da var. Aşağıdaki npe() fonksiyonu çağırıldığında NullPointerException fırlatır.
Ayrıca java dünyasından çağırdığımız fonksiyonların da NullPointerException fırlatma potansiyeli olduğunu unutmamak gerekir.