Inline Function Kullanımı — Kotlin

Gorkem Ozgur
ÇSTech
Published in
4 min readDec 30, 2022
https://kotlinlang.org/

Herkese merhaba, bu yazımda Kotlin dilinde geliştirme yapan yazılımcılar olarak kullanımının basit ve yarattığı farkın büyük olduğunu düşündüğüm Inline Function ( Satıriçi Fonksiyon ) dan bahsedeceğim.

Inline Function a geçmeden önce anlamamız gereken bir konu olan Higher Order Function (Yüksek Mertebe Fonksiyon) ve Lambda dan bahsetmem gerekiyor.

Higher Order Function ve Lambda Gösterimi Nedir?

Kotlin dilinde fonksiyonlar first-class fonksiyonlardır. Bir programlama dilinin fonksiyonlarının first-class olması demek o programlama dilinin değişken olarak fonksiyon tutma yada fonksiyon içerisinde parametre olarak fonksiyon geçmemize izin vermesidir.

Higher Order Function first-class fonksiyonlarda parametre olarak bir yada birden fazla fonksiyon alan yada return eden fonksiyonlara verilen isimdir.

Basit bir örnek ile açıklayalım. Elimizde birden fazla rastgele integer değerler olduğunu ve bu değerleri Higher Order Function kullanarak sıralayıp integer listesine dönüştürmek istediğimizi düşünelim.

fun numberArranger(vararg number: Int, arrangedList: (List<Int>) -> Unit) {
arrangedList.invoke(number.toList().sorted())
}

Yukarıdaki oluşturduğumuz kod bloğunda arrangedList parametresi bir fonksiyondur ve parametre olarak integer listesi alır. numberArranger bir Higher Order Function dır ve görevi aldığı integer değerleri listeye çevirip sıralayıp arrangedList fonksiyonuna parametre olarak vermesidir.

Peki Higher Order Function çağırırken fonksiyonu nasıl parametre olarak vereceğiz? Bu kısımda yardımımıza Lambda geliyor.

Lambda anonim, isimsiz fonksiyonlardır. Lambda yı bir değişkene eşitleyebiliriz yada fonksiyona parametre olarak geçebiliriz.

Önceki örnekteki fonksiyonu çağırarak gösterelim.

numberArranger(1, 5, 2, 3, 4, arrangedList = { list ->
list.forEach { number ->
println(number)
}
})

Yukarıdaki kod bloğunda 1 den 5 kadar olan rakamları rastgele verip bize bu rakamları sıralanmış halde döndürcek olan anonim fonksiyonu lambda gösterimi ile belirttik ve bu lambda fonksiyonunun her bir rakamı konsola yazdırmasını söyledik.

Peki lambda gösterimi yerine direkt oluşturduğumuz başka fonksiyonu parametre olarak vermek istersek? Bu durumda yardımımıza “::” gösterimi geliyor.

fun main() {
numberArranger(1, 3, 5, 2, 3, 4, arrangedList = ::printNumbers)
}

fun printNumbers(list: List<Int>){
list.forEach {
println(it)
}
}

Dikkat edersek bu örnekteki forEach metodu da int parametreli fonksiyon alan bir Higher Order Function dır ve println fonksiyonunu lambda ya çevirmek istersek aşağıdaki şekilde olacaktır.

fun main() {
numberArranger(1, 3, 5, 2, 3, 4, arrangedList = ::printNumbers)
}

fun printNumbers(list: List<Int>){
list.forEach(::println)
}

Inline Function Nedir?

Higher Order Function larda parametre olarak verdiğimiz fonksiyonlar JVM tarafından runtime da Function interface ini extend eden anonim class objesi üretir. Bir örnek ile gösterelim.

fun higherOrderFunction(callback: () -> Unit) {
callback()
}

Yukarıdaki kod bloğu build alındıktan sonra aşağıdaki şekilde görünecektir.

public static final void higherOrderFunction(Function callback) {
callback.invoke();
}

Aynı şekilde bu fonksiyonu çağırırken nasıl gözükeceğini yazalım.

fun example() {
println("I am outside invoke")
higherOrderFunction {
println("I am inside invoke")
}
}
public static final void example() {
System.out.println("I am outside invoke");
higherOrderFunction(new Function() {
@Override
public void invoke() {
System.out.println("I am inside invoke");
}
});
}

Örnekte gördüğümüz üzere biz her yukarıdaki higherOrderFunction ı çağırdığımızda yeni bir Function() objesi oluşuyor. Burdaki problem biz birden fazla bu fonksiyonu çağırmak istediğimizde her seferinde yeni bir obje oluşturularak memory şişirilecek ve garbage collector a düşen yük artacak ve dolayısıyla performans yavaşlayacak. Bu sorunun önüne geçmek istediğimiz zaman yardımımıza Inline Function geliyor.

Inline Function kullanarak compilera Higher Order Function a parametre olarak verdiğimiz fonksiyonun bir objesini oluşturmak yerine fonkisyonun içerisindeki kodu kopyalayıp Higher Order Function ın içerisine yerleştirmesini söyleyebiliriz. Önceki verdiğimiz örneği Inline Function olarak yazıp build alındıktan sonra nasıl gözükeceğine bakalım.

inline fun higherOrderFunction(callback: () -> Unit) {
println("I am higher order function")
callback()
}

Yukarıdaki fonksiyonu çağırdığımız yer aşağıdaki şekilde gözükecektir.

public static final void example() {
System.out.println("I am outside invoke");
System.out.println("I am inside invoke");
}

Bu işlemi bir döngü içerisinde bir çok defa yaptığımızı düşünelim, inline kullanımı olmadan döngüdeki tekrar sayısı kadar obje oluşturup garbage collectorun bu objeleri silmesi gerekecekti. Inline kullanımı sayesinde yeni obje oluşturma yükünü almış olduk.

Inline Function Diğer Avantajları

Local Olmayan “return” e izin verir.

Higher Order Functiona parametre içerisinde verilen Lambdanın kod bloğunda Higher Order Functionı return edemiyorduk, inline kullanımı sayesinde aşağıdaki şekilde return edebiliyoruz.

fun higherOrderFunction(callback: () -> Unit) {
callback()
}
fun example() {
higherOrderFunction {
return // Compiler gives error.
}
}

Inline Function kullandığımızda ise compiler tarafından hata almayıp fonksiyonu return edebiliyoruz.

inline fun higherOrderFunction(callback: () -> Unit) {
callback()
}
fun example() {
higherOrderFunction {
return // OK.
}
}

Peki Inline Function kullanmak istiyoruz fakat lokal olmayan dönüşe izin vermesini istemiyorsak ne yapmalıyız? Bu durumda crossinline yardımımıza geliyor.

inline fun higherOrderFunction(crossinline callback: () -> Unit) {
callback()
}
fun example() {
higherOrderFunction {
return // Compiler gives error.
}
}

Inline vermek istemediğimiz parametreler tanımlayama izin verir.

Inline oluşturduğumuz ama istenilen parametreyi inline yapmak istemiyorsak noinline kullanımı devreye geliyor.

inline fun higherOrderFunction(
callback: () -> Unit,
noinline callback2: () -> Unit
) {
callback()
}

Generic tip alan fonksiyonlarda fonksiyon içerisinde tipe erişim sağlar.

Reified olarak belirtilen tip ile inline function kullanırsak generic verilen tipe erişebiliriz.

inline fun <reified T> example() = T::class.java

Inline Function Dezavantajı

Bulunduğu classtaki değişkenlere erişemezler.

Inline Function lar bulunduğu classtaki değişkenlere erişemezler. Değişkenlerin public yada private olması fark etmeksizin.

Bu yazımda Inline Function ile ilgili bahsedeceklerim bu kadardı. Bir sonraki yazımda görüşmek üzere 👋

--

--