Kotlin’de Yüksek Seviye Fonksiyonlar (High Order Functions)

 In Development

Merhaba

2010’da Oracle, Sun Microsystems’ı satın aldığından beri Oracle ile Google arasında bir Java savaşı sürmekteydi. Oracle, Google’ı Java’nın ücretsiz olmayan özelliklerini kullanmakla suçlayarak büyükçe bir dava açtı falan filan hikayeyi biliyorsunuzdur hepsini anlatmama gerek yok sanırım. 2 sene önce GoogleIO 2017 etkinliğinde Kotlin, Google tarafından resmi programlama dili olarak ilan  edildi. O gün bugündür Android Geliştiricileri olarak Kotlin öğreniyoruz ve öğrenmeye devam ediyoruz.

“Kotlin fonksiyonel dil özelliklerine sahiptir” cümlesini pek çok Kotlin ve Android hayranından duymuş olabilirsiniz (Ben dahil). Nedir yani bu fonksiyonel dil özellikleri hadi örnek ver hadi… diyorsanız, toplanın yamacıma. Bu yazıda, Kotlin’in fonksiyonel dil özelliklerinden birisi olan yüksek seviye fonksiyonların kullanımını anlatacağım.

Fonksiyonel dillerde, fonksiyonlar özeldir tek başlarına bireylerdir. Literatürde bu first class tabiri ile ifade edilir. Yani String, Integer veya bir Sınıf ile fonksiyonlar aynı seviyededirler. Fonksiyonlara parametre olarak String veya Integer yollayabildiğimiz gibi first class fonksiyonlara sahip dillerde parametre olarak fonksiyon da yollayabiliriz. Fonksiyona parametre olarak fonksiyon yolluyoruz yani. Aynı şekilde başka fonksiyonlardan return tipi olarak fonksiyon da döndürebiliriz. Fonksiyonlar Java’nın aksine fonksiyonel dillerde herhangi bir sınıf içerisinde yer almak zorunda değillerdir. Fonksiyon çağıran fonksiyonlara yüksek seviye fonksiyonlar ismi verilir ve fonksiyonel diller yüksek seviye fonksiyon özelliğine sahiptirler. Kotlin de doğal olarak bu özelliğe sahiptir. Ayrıca fonksiyonel dillerde fonksiyonlar veri yapılarında ve değişkenlerde tutulabilirler. Özet olarak High Order Functions, Kotlin’in gözde özelliklerinden birisidir. Şimdi önce küçük bir örnek ile daha iyi açıklayacağım. Ardından Android’de real-life kullanımını göstererek pekiştireceğim. İzninizle, Başlayalım…

 

Parametre olarak fonksiyon kabul eden bir fonksiyonun tanımlanması aşağıdaki gibi yapılır.

fun passMeFunction ( text:String , function : ( ) -> Unit ) {
// do something
//execute the function
function()
}

Bu fonksiyon, şu 5 şekilde çağırılabilir:

passMeFunction ( “text” ) { print ( it ) }
passMeFunction ( “text” ) { s -> print ( s ) }
passMeFunction ( “text” , { print ( it ) } )
passMeFunction ( “text” , { s -> print ( s ) } )
passMeFunction(“text”, ::print )  // En pratik versiyon tabiiki bu. it veya herhangi bir başka değişkene gerek kalmaksızın Fonksiyon Referansı kullanarak kodu daha da basitleştirebiliriz.

KISS : Keep It Small Stupid hell yeeaa

 

Ben açıkçası bu özelliğe ihtiyaç duyduğumun farkında bile değilmişim. Kullanmaya başladığımda farkettim ki pek çok yerde high order function kullanabilirim.Özellikle orta ve daha büyük ölçekte bir proje yazarken pek çok defa aynı koda başka Activitylerde Fragmentlarda Sınıflarda ihtiyaç duyarsınız. Bu normaldir. Mesela kullanıcı silme işlemi kullanıcı listesinden de gerçekleşebilir kullanıcı detay sayfasından da. Ancak kopyala yapıştır yapmaya başlarsanız büyük projede ilerleyen safhalarda boğulabilirsiniz. Çöp kod üretebilirsiniz ve kod yönetimini kendi elinizle zorlaştırabilirsiniz. Her projeyi başından düzgün yazmanızı öneririm ki ilerleyen zamanda refactor için çok daha fazla zaman harcamanız gerekmesin.

Kullanım Örneği

Real-life örneğe gelirsek. Peakup’ta çalışanların hızlıca izin alabilmelerini, izin sürecini takip edebilmelerini, takım liderlerinin ve insan kaynaklarının da izin süreçlerini kolayca yönetebilmelerini sağlayan bir Android uygulamamız var. Leave Management. Bu uygulamamızı yazarken bir sorunla karşılaştım. İzin silme, izin onaylama ve izin reddetme işlemleri için hemen hemen aynı fonksiyonu yazdığımı ve gereksiz kod tekrarı yaptığımı farkettim. 3 operasyonda da İzin detay DialogFragment’ını önce kapatıp sonra silmek / reddetmek / onaylamak istediğinize emin misiniz? diye soran bir dialog çıkartıyordum. Kullanıcı onay butonuna basınca da ilgili fonksiyon aracılığı ile backende request yolluyordum. Yazılan fazladan kodu farkettiğimde High Order Function özelliği geldi aklıma. Çünkü 3 fonksiyonda da sadece Dialog’da yazan text ve çağırılan request fonksiyonu farklıydı. Ve şöyle bir Fonksiyon yazdım:

private fun showAlertAndOperate(@StringRes stringId: Int, leave: Leave, func: () -> Unit) {
leaveDetailsDialogFragment.dismiss() // Close Leave Details Dialog Fragment
val text = getString(stringId, leave.User.getNameSurname(), LeaveDate.getDayAndTimeByFormat(leave.CreatedAt, LeaveDate.prettyFormatLongDateTime), leave.Reason.Name)
showAlertDialog(text, DialogInterface.OnClickListener {_, which ->
if (which == DialogInterface.BUTTON_POSITIVE) {
func()
/* func() is sent as parameter.
When dialog shows up and user tap OK button, func() is fired here */
}
})
}
view raw show.kt hosted with ❤ by GitHub

showAlertAndOperate ismini verdiğim bu fonksiyon, 3 adet parametre alıyor. İlk parametresi bir Int ancak annotation olarak StringRese sahip. Yani bu fonksiyona göndereceğiniz ilk parametre R.string.xxx gibi bir string id olacak. İkinci parametre bir leave objesi. Son parametre ise işlemi yapacak olan fonksiyon. Son parametrede eğer izin silme işlemi yapacaksak izin silme requestini yapan fonksiyon, izin onaylama işlemi yapacaksak onaylama requestini yollayan fonksiyon çağırılacak yani.

showAlertAndOperate fonksiyonu önce izin detay dialog fragmentını kapatıyor. Ardından normal Dialog içerisinde gösterilecek olan texti StringRes ve Leave parametrelerini kullanarak hazırlıyor. Ardından bu texti showAlertDialog fonksiyonuna yollayarak Global alertdialogun çıkmasını sağlıyor. Dialogun onay butonuna basıldığı takdirde ise fonksiyona parametre olarak gönderilen fonksiyon çalışıyor.

override fun onLeaveApprove(leave: Leave) =
showAlertAndOperate(R.string.are_you_sure_to_accept_leave, leave) { confirmLeave(leave, MODE_ACCEPTED) }
override fun onLeaveDecline(leave: Leave) =
showAlertAndOperate(R.string.are_you_sure_to_decline_leave, leave) { confirmLeave(leave, MODE_DECLINED) }
override fun onLeaveDelete(leave: Leave) =
showAlertAndOperate(R.string.are_you_sure_to_remove_leave, leave) { deleteLeave(leave) }
view raw OverrideMethods.kt hosted with ❤ by GitHub

 

Yukarıda gördüğünüz fonksiyonlar ise İzin detay dialog fragmentına ait interface içerisinde bulunan buton onClick işleminde çalışan callbackler. Gördüğünüz üzre onLeaveApprove‘da confirmLeave fonksiyonu accepted modunda, onLeaveDecline‘da confirmLeave fonksiyonu declined modunda çağırılmış. onDelete’te ise deleteLeave() fonksiyonu çağırılmış. showAlertAndOperate fonksiyonunda belirtilen func() fonksiyonu yerine bu fonksiyonlar çağırılacak.

Kodu kopyala yapıştır yapmamak için tabiiki pek çok farklı yöntem de mevcut. Bu yazıda bu yöntemlerden sadece birinden bahsedebildim. En güzel yöntem budur golden keydir gibi iddialara sahip değilim. Sadece bu seferlik bunu tercih ettim ve sizlerle paylaşmak istedim.

Bol kodlu günler dilerim.

Önerilen Yazılar
İletişim

Start typing and press Enter to search