Higher-Order Fonksiyonlar ve Kullanım Senaryoları | Android-Kotlin

Furkan Aşkın
5 min readMay 28, 2019

--

Lambda

Bilgisayar programlamada, anonim bir fonksiyon(lambda) herhangi bir tanımlayıcıya gerek duymayan fonksiyondur. Lambda genellikle Higher-Order(Üst düzey) fonksiyonlara iletilen argüman olabilir ya da bir sonuç döndürmesi gereken Higher-Order fonksiyonun sonucunu oluşturmak için kullanılır.

Fonksiyon sadece bir kez veya sınırlı sayıda kullanılacak ise isimlendirilmiş bir fonksiyon kullanmak yerine lambda kullanmak syntax açısından kolaylık sağlıyor. Lambda, fonksiyonel programlama dillerinde veya diğer birinci sınıf fonksiyonlara sahip dillerde bulunabilir.

Birinci Sınıf Fonksiyonlar : Bu fonksiyonlar değişkenlerde veya veri yapılarında saklanabilirler, argüman olarak iletilebilir veya diğer Higher-Order fonksiyonlardan geri döndürülebilir.

Lambda içeren programlama dilleri listesine buradan ulaşabilirsiniz.

Kod kısmında tanımlarken;

(Tür, Tür, Tür) -> Geri Dönüş Türü

şeklinde tanımlanırlar.

Normal bir fonksiyonla yapılabilecek işlemi lambda ile nasıl yapabiliriz ufak bir örnek ile başlayalım :

Görüldüğü gibi aslında carpim fonksiyonu ile yapabileceğimizi lambda kullanarak yapabiliyoruz ve yukarıda bahsettiğim gibi bunu bir değişkende tutabiliyoruz. Çok daha basit bir örnek üzerinden açıklayarak devam edelim :

{a -> a*a}

Bu kısım aslında kendi başına bir fonksiyon. a değişkeninin türünü ve geriye ne döndürmesi gerektiğini (Int)-> Int kısmından anlıyor.

Higher-Order Fonksiyonlar

Higher-Order fonksiyonlar parametre olarak bir veya birden fazla fonksiyon alırlar ya da sonuç olarak bir fonksiyonu geri döndürürler. Nasıl mı?

Burada Higher-Order fonksiyonumuz islemTuru, sayi1, sayi2 ve birde islem fonksiyonunu parametre olarak alıyor. Süslü parantezler içerisinde öncelikle işlem türünü yazdırıyor ve ardından işlemi yapıyor.

inline/noinline nedir?

noinline : Bir Function instance’ı oluşturur ve yerine getirmesi istenilenleri bu Function instance’ı içerisinde tamamlar.

inline : Herhangi bir instance oluşturmadan doğrudan yerine getirmesi istenilenleri tamamlar.

**Ufak bir not : inline ile tanımlanan fonksiyonlar aynı class’ta olsanız bile private değişkenlere erişemezler.**

Yukarı anlatılanları görmek adına bir örnek üzerinde açıklayayım :

Yukarıdaki fonksiyonun Java karşılığı şu şekilde :

Bu fonksiyonu Kotlin’de aşağıdaki gibi çağırıyoruz :

Arkaplanda derleyici yeni bir Function instance’ı yaratıyor ve invoke fonksiyonunu Override ederek içerisine bizim yazdığımız fonksiyon bloğunu yerleştiriyor.

Aynı şekilde fonksiyonu inline tanımlayacak olursak :

Kullanım açısından bir fark olmayacak yine aynı şekilde fonksiyonu çağıracağız:

Ama artık yeni bir Function instance’ı yaratılmadan doğrudan tanımladığımız fonksiyon bloğu kullanılacak.

Bir Higher-Order Fonksiyonun başına herhangi bir keyword eklemezseniz default olarak noinline tanımlanır. Eğer ki başına inline eklerseniz, fonksiyon inline olarak çalışır. Arasında sonuç olarak bir fark yok, aynı sonucu elde edebiliyoruz fakat derleme süreleri arasında oldukça büyük farklar var. Higher-Order fonksiyonunuzun daha hızlı çalışmasını istiyorsanız inline tanımlamanız daha doğru olacaktır.

Başka bir örnek ile performans farkına bir göz atalım.

Yukarıdaki örnekte repeat ve noinlineRepeat şeklinde iki fonksiyon görüyoruz. repeat fonksiyonumuz 0,335 Nanosaniye’de tamamlanırken, noinlineRepeat fonksiyonumuz 153.980.484,884 Nanosaniye’de tamamlanıyor. Aralarındaki bu büyük performans farkından dolayı mümkün olduğunda inline ile tanımlama yapmanız, performans açısından oldukça yararlı olacaktır.

crossinline ne işe yarar?

crossinline’ı anlamlandırabilmek için öncelikle “lokal olmayan dönüşler”i anlamamız gerekiyor.

Yukarıda bir adet inline fonksiyonumuz var ve parametre olarak Unit dönüş yapan bir abc fonksiyonu alıyor. doSomething() fonksiyonu ise belirli adımları takip etmesini istediğimiz normal bir fonksiyon. Çalıştırdığınızda fark edeceksiniz ki println(“doSomething end”) kısmına giremedi.

Bunun sebebi return ettiğimiz kısımda biz inline fonksiyonumuza “lokal olmayan dönüş” yapabilme izni verdik ve bu dönüşü sağlayarak derlemeyi tamamladı. Yukarıdaki kodun java karşılığını bir inceleyelim :

Gördüğünüz gibi burada println(“doSomething end”) kod bloğu yok, sebebi demin söylediğim gibi lokal olmayan dönüşe izin vermiş olmamız.

Peki bunu nasıl önleyeceğiz?

Bunu önlemek için yapmamız gereken tek şey crossinline kullanmak.

inline fonksiyonumuzu tanımlarken parametre olarak verdiğimiz abc()’un başına crossinline eklersek bu sorundan kurtulmuş oluyoruz. Kısacası crossinline bize lokal olmayan dönüşleri engellememizi sağlıyor.

Peki, canlı bir projede nerelerde kullanabiliriz?

Bir kaç örnek vermek gerekirse:

  • Örneğin RecyclerView Adapter’ında onClick yazarken kullanılabilir.

Değişkenlere aşağıdaki gibi erişilebilir.

  • Veya try/catch blocklarını uzun uzun yazmak yerine şöyle bir inline fonksiyon yazılabilir.

Şu şekilde kullanılabilir :

Sonuç

  • Syntax kolaylığı sağlamak için kodunuzda lambdalara yer verin.
  • Higher-Order fonksiyon tanımlarken mümkün olduğunca noinline yerine inline tanımlamaya çalışın.
  • Lokal olmayan dönüşleri engellemek istiyorsanız crossinline kullanın.
  • Son olarak projenizde sürekli kullanacağınız alertDialog oluşturma, toast mesaj basma, network kontrolü, try/catch vb. yapılar için gerek Kotlin Extensions gerek Higher-Order Functions and Lambdas kullanmaya özen gösterin.

Bu yazım burada sonra eriyor, vakit ayırıp okuduğunuz için teşekkür ederim, beğendiyseniz alkışlamayı unutmayın!

--

--