Kotlin’e Giriş 3- Functions(Fonksiyonlar)

Muhammed Burak Çakır
Android Türkiye
Published in
6 min readFeb 19, 2020

Merhabalar, Kotlin’e Giriş serimize fonksiyonlar ile devam ediyoruz.

Serinin ikinci yazısına buradan ulaşabilirsiniz : Kotlin’e Giriş 2- Control Flows

Fonksiyonlar sıkça kullanılan yapılarda olsa, mantığından bahsetmek gerektiğini düşünüyorum.

Fonksiyon nedir?

Programlamada fonksiyonlar, belli kodları bir arada tutup farklı amaçlara göre yönetmeyi ve tekrardan kaçınmayı sağlayan kod bloklarıdır.

Aynı matematikte kullandığımız fonksiyonlar gibi istenilen parametrelere argüman alıp belli çıktılar üretebilir.

Örneklemek gerekirse,

f(x,y) = 5x + y + 2 fonksiyonumuz olsun. İsmi functionXY , amacı ise verilen 2 tane değişkenden sonuç üretmek olsun.

x = 2 ve y = 3 için

f(2,3 ) = 5.2 + 3 + 2= 15 sonucunu verir. Programlamada da amaç farklı değildir.

Fonksiyonlarımızın isimleri vardır, argüman verilirse buna göre yaptığı işlemler ve çıktılar vardır.

Daha fazla teoriğe girmek hepimizin kafasını karıştıracaktır. 😊

Kotlin’de fonksiyon tanımıyla devam edelim.

Fonksiyon tanımlama :

Kotlin’de fonksiyonlar sırasıyla

  • “fun” anahtar kelimesi
  • Fonksiyon ismi ,
  • Fonksiyonun parametre ve parametre tipi
  • Fonksiyon dönüş tipi
  • Body sırasıyla yazılırlar.
fun squareOfNumber(number : Int) : Int {
return number * number
}

Java’da tüm methodlar sınıfların içinde bulunmalıydı, oradan çağırım yapılıyordu.

Kotlin aynı zamanda fonksiyonel programlamayı desteklediğinden dolayı, sınıf içermeyen bir Kotlin dosyasından da fonksiyonları çağırabiliriz.

Kotlin’de, Javanın aksine fonksiyon parametreleri default value(değer) alabilirler.

Sağladığı avantaj, default değer alan parametreye o fonksiyon her çağırıldığında argüman göndermek zorunda değiliz.

Çünkü argüman gönderilmediğinde, tanımladığımız default değer, parametrenin değeri olarak kabul edilir.

fun setPersonInfo(name : String, surName : String, age : Int, gender : String){
}

fonksiyonumuz olsun ve 4 tane parametre alsın. Burada default değer tanımlamadığımız için fonksiyon çağırıldığında tüm parametrelere argüman gönderilmelidir.

Function Default Arguments

2. satırda hata alırız. Çünkü, 3. parametre Int değer beklerken biz String değer gönderdik. Bu hatayı engellemek için default değer ataması yapabiliriz.

age değişkenine default değer olarak 30 tanımladık. Artık fonksiyonu çağırdığımızda argüman göndermezsek, age = 30 olarak kabul edilecek.

Tekrardan hata aldık. Fakat almamamız gerekiyordu değil mi?

Function Named Arguments

Derleyici, fonksiyona bakarken parametreleri sırayla tarayacak ve “Male” argümanını age değişkeni ile eşleştirmeye çalışıp “Type mismatch” hatası verecektir. Bu yüzden, sırayla atama yapmıyorsak, hangi parametreye değer atadığımızı belirtmeliyiz. Bu işleme named argument diyoruz.

Bu yöntemle, overloading(aşırı yükleme) yapabiliriz, her bir parametre durumunu ele alarak tekrar tekrar fonksiyon yazmayı engelleriz.

Sonuç olarak;

  • “age” default argument,
  • gender named argument olarak kullanılmıştır.

Named arguments olması için, parametre atlanmasına gerek yoktur. Basitçe parametreyi isimlendiriyoruz.

Variable number of arguments (Varargs)

Eğer fonksiyona verilecek parametreler belli değilse, “vararg” kullanabiliriz. Aslında boyutu belli olmayan bir liste diyebiliriz.

Bir fonksiyonda sadece 1 parametre vararg olabilir.

O yüzden argüman olarak farklı tipte değerler veya diziler verebiliriz.

Tek bir tipte değer gönderimi için:

Array olarak verilecekse, arrayOf’un başına spread(*) operatörü koyulması gerekir.

Farklı tipte parametreler için, vararg tipi Any olabilir veya Genericler kullanılabilir.

Vararg’tan önce ve sonra da parametre verilebilir.

Sonra parametre vereceksek, named argument kullanmak zorundayız. Çünkü compiler, vararg nerede bitecek bilemez.

Önce parametre vereceksek, named argument kullanmak zorunda değiliz. Burada sıra hiyerarşisi sağlanır.

vararg değişkenlere index ile ulaşılabilir.

Unit-returning functions

Kotlin’de, hiçbir değer döndürmeyen fonksiyonlar için Unit anahtar kelimesini kullanırız. Java’da “void” anahtar kelimesinin karşılığıdır.

Single-expression functions

Bildiğimiz gibi, if, for gibi kontrol bloklarında, tek bir satır kullanacaksak süslü paranteze gerek olmadan yazabiliyorduk. Kotlin’de, fonksiyonlar tek bir satır kod içeriyorsa, expression olarak yazabiliriz.

fun squareOfNumber(number : Int) : Int = number * number

Infix notation

Daha okunabilir bir kod yazılımı sağlar. Fonksiyonun başında infix anahtar kelimesi kullanılır.

Infix fonksiyonlar :

  • Member function (üye fonksiyon/bir sınıfa ait fonksiyon) veya extension fonksiyon olmalıdır. Extension fonksiyon detaylarını aşağıda açıklayacağım.
  • Infix fonksiyonlar 1 parametre almak zorundadır. Daha fazla veya daha az parametre alamaz.
  • Infix fonksiyonlar default değer kabul etmezler ve vararg değişken kabul etmezler.

Fonksiyonun başına “infix” anahtar kelimesi ile tanımlanırlar.

fonksiyonu companion object içine alarak nesne oluşturmadan Class ile erişimi sağladık.

“and” ve “or” operatörleri de infix olarak kullanılabilir.

Function scope

Member ve Top Level Fonksiyonlar

Java dilinden aşina olduğumuz üzere, her fonksiyonun ait olduğu bir sınıf vardı. Kotlin dilinde ise, fonksiyonel programlamanın desteklenmesi sebebiyle sınıflara bağımlı olmayan fonksiyonlar yazabileceğimizi söylemiştik.

Sınıfın içinde yazılan fonksiyonlara member function(üye fonksiyon) diyoruz.

Eğer bir fonksiyon, sınıf içinde değilde bir dosya içinde tanımlanıyorsa, buna “top level function” deriz.

Üye fonksiyonlar aslında methoddur. C++ dilinde member function, Java dilinde method olarak geçerler.

Local Fonksiyonlar

Kotlin’de, fonksiyon içinde başka bir fonksiyon tanımlayabiliriz. Bu fonksiyonlara local fonksiyonlar ismi verilir.

Local Fonksiyonları kullanmamıza sebep olarak :

  • Fonksiyonlara erişme metodu olan Reflection yöntemini engellemek,
  • Fonksiyon grupları için belirsiz ilişkiler içeren class yapıları oluşturmayı engellemek,
  • Class ile fonksiyon arasındaki bağımlılıkları azaltmak diyebiliriz.

Fonksiyonları, main fonksiyonun altında veya Class kullanımında, konumundan bağımsız olarak çağırabiliyorduk. Local fonksiyonlarda ise, fonksiyon çağırıldığı kod bloğunun üstünde tanımlanmak zorundadır.

Local fonksiyonlar, onu kapsayan fonksiyonların değişkenlerine erişebilir.

Bir fonksiyon Generic tip aliyorsa, Generic Function olarak adlandirilir.

fun <T> setColor(colorCodeId: T) {
}

Extension Fonksiyonlar

Projelerimizde çoğu zaman kullandığımız kütüphanelerin kodlarını geziyoruz, override ettiğimiz fonksiyonları tanımaya çalışıyoruz.

Extension fonksiyonlarla; sınıfları extend etme zorunda kalmadan, kodlarına dokunmadan metodlarımıza uygulayabiliriz.

Bu yöntemle yazdığımız fonksiyonlara, kullandığımız sınıfın fonksiyonuymuş gibi davranırız, fakat aslında o sınıfa bağlı değillerdir.

Hem değişken ile hem değer ile çağırılabilirler.

Faydaları :

  • Kullanıcıya, ihtiyaç olan sınıfla bağlılık kurmadan kullanabilmeyi sağlar.
  • Daha kısa ve okunabilir kod blokları sağlar.

Kullanım :

fun Type.funName() ..

Burada String.generateNewString() ile fonksiyonumuzu tanımladık ve String sınıfından bir değişken kullanacağımızı belirttik. Değişkeni işaret edip kullanmak için “this” anahtar kelimesini kullanıyoruz.

Bu fonksiyon, kendisine verilen bir String değeri harflerine ayırır ve rastgele bir charArray oluşturur. İnternette bulunan örneklerden daha iyi bir örnek vermeliyim diye düşündüm :)

Infix fonksiyonları anlattığımızda, Extension fonksiyonlar ile birlikte kullanılabileceklerini söylemiştik.

Bu örneğimizde, Infix, extension ve local fonksiyonları beraber kullanalım.

Infix ve Extension fonksiyonu beraber kullanarak;

  • 2 parametre kullanabildik. Infix fonksiyonlarda sadece 1 parametre kullanılıyordu.
  • “.” Operatörü kullanmak zorunda kalmadık.
  • Daha okunabilir bir kod yazabildik.

Extension fonksiyonları ardışık olarakta kullanabiliriz.

Extension fonksiyonlar bir sınıfın içerisinde yazıldılar ise sadece o sınıf içinde kullanılabilirler. Fakat inheritance(kalıtım) olduğu durumda override edilebilir.

Infix extension fonksiyonlar, expression formunda kullanilabilir.

infix fun String.extPlus(otherString: String): Int = this.toInt() + otherString.toInt()

Higher-order fonksiyonlara giriş yapmadan önce First Class Citizen(Birinci Sınıf Üye) kavramına göz atalım.

Yapılar

  • Değişkene değer ataması olarak kullanılabiliyor
  • Fonksiyona parametre olarak verilebiliyor
  • Fonksiyonun geri dönüş değeri olabiliyorsa, First Class Citizen olarak adlandırılırlar.

Kotlin’de fonksiyonlarda FCC’dır.

Fakat,

Biz burada, fonksiyonları parametre olarak göndermiyoruz. Onların return ettiği değerleri parametre olarak gönderiyoruz. Bu yüzden :

aslında bu 2 fonksiyon aynıdır.

Higher-order functions

Higher-order fonksiyonlar temelinde çok geniş bir konudur. Dolayısıyla, burada temel anlatım yapacağım.

Higher-order fonksiyonlar, parametre olarak fonksiyon alabilir ve fonksiyon geri döndürebilir.

Birbirine yakın kodlar içeren fonksiyonları tek tek yazıp okunabilirliği düşürüp programımızı karışık hale getirmek yerine, higher-order fonksiyonlar ile istenen kod bloklarını fonksiyonlara geçirebiliriz.

Alparslan Selçuk Develioğlu’nun, detaylı bir şekilde anlattığı Higher-order fonksiyonlar yazısını tavsiye ediyorum:

Higher-order fonksiyonlarda, parametre olarak verilen fonksiyonun tanımı ve çağrımı yapılır.

Higher-order fonksiyonu başka yerden çağırırken ise, body farklı yollarda fonksiyona gönderilir.

Önce parametre olarak nasıl verildiklerine bakalım.

Yöntem :

Fonksiyon ismi : (parametreAdı : parametreTipi) -> Fonksiyon dönüş tipi

Burada getSurName, higher-order fonksiyona parametre olarak verildi.

Parametre olarak gönderilen fonksiyonlar, tanımlandıkları fonksiyonun içinde çağırılmalıdırlar. Yoksa redundant(gereksiz) kod kullanımı olur ve tekrar çağırılmazlar.

Higher-order fonksiyonlara 3 şekilde body gönderebiliriz.

1- Fonksiyon çağırımında kullanmak

Burada değişkene atama yapmadan, fonksiyon çağırımında kod bloklarıyla gönderildi.

2- Değişkene atamak, fonksiyona değişken olarak göndermek

Burada higherOrderFunction değişkeni ile printUserInfo’ya gönderildi.

3- Anonymous Fonksiyon

Birden fazla değişken alan higher-order fonksiyonu örnek kullanımı :

news.filterNews { filterType, getFilterName ->
}

Fonksiyonu, son parametre olarak yollayacaksak, higher-order fonksiyonunun parametrelerinin dışında da tanımlanabilir. Daha okunabilir kod görünümü sağlar.

news.getNewsFromServer("FoxTv", newsType) {
println(this.toString())
}

Değişken ismi belirtilmeden, sadece değişken tipi belirtilerek tanımlanabilir.

fun getItemClickListener(onClick: (String) -> Unit) {

Tabii ki higher-order fonksiyonların kullanımları bu kadar ile sınırlı değil. Sadece kendisi hakkında sayfalarca yazılar hazırlanabilir. Amacım, giriş seviyesinde tanıtmak ve öğretmek olduğu için, konseptin çok dışına çıkmamam gerektiğini düşündüm. Bu yazımızda burada bırakalım.

Faydalı olması dileğiyle. :)

Kaynaklar :

1- Kotlinglang

2- Codemy Github

3- Kapak Resmi : CalliCoder

--

--