Scala’da Koşul İfadeleri

Herkese merhaba!

Bu yazımda programlamanın en temel konularından olan koşul ifadelerinden bahsedeceğim. Anlatacaklarım daha çok bu ifadelerin Scala’daki işleyişi ve diğer dillerden, özellikle Java’dan farkları hakkında olacak.

Haydi başlayalım.

if Özel Kelimesi

if özel kelimesi neredeyse bütün programlama dillerinde var olan, İngilizcede eğer anlamına gelen bir kelime. Yaptığı şey de kodunuzun belli koşul(lar)a göre farklı davranmasını sağlamak. Scala’daki söz dizimi de Java’daki ile birebir aynı. Basitçe birkaç örnek ile nasıl göründüklerine bakalım.


if (1 == 1 && (true || false) {
// Bu her zaman çalışacak
val mesaj = "1 == 1"
println(mesaj)
} else if (2 != 2) {
// Bu hiç çalışmayacak
println("2 != 2")
} else {
// Bu hiç da çalışmayacak
println("1 != 1")
}
// Gövdede tek bir ifade olduğunda süslü parantez kullanmayabilirsiniz.
if (1 == 1 && true) println("1 == 1") else println("1 != 1")

Gördüğünüz gibi çok sıradışı bir şey yok. Süslü parantez kullanımı konusunda önerim; süslü parantezleri sadece eğer 14. satırdaki ifade kadar basit bir ifade yazacaksanız kullanmayın ve ifadenizi bu şekilde tek satırda yazın. Bunun dışındaki durumlarda if, else if ve else gövdelerinde süslü parantezler kullanın.

Şimdi Scala’daki if’in farklı bir yönüne bakalım. Scala’da koşul ifadeleri, döngü ifadeleri, süslü parantezler içine yazılmış birden fazla ifadeden oluşan bloklar gibi birçok yapı aslında yorumlanır ve bir değer üretir. Yani if için konuşacak olursak, bir if-else if-else topluluğunun bütünün ürettiği bir değer vardır. Bunun Java ile karşılaştırmalı bir örnek ile daha kolay anlaşılacağını düşünüyorum.


// Java
String metin = "merhaba";
int uzunlukSeviyesi; // 1, 2 veya 3
if (metin.length < 2) {
uzunlukSeviyesi = 1;
} else if (metin.length < 4) {
uzunlukSeviyesi = 2;
} else {
uzunlukSeviyesi = 3;
}
// Scala
val metin = "merhaba"
val uzunlukSeviyesi = if (metin.length < 2) {
1
} else if (metin.length < 4) {
2
} else {
3
}

Örnekte görebileceğiniz gibi, if ile başlayıp else bloğunun kapanan süslü parantezi ile biten kod parçasının bütünü aslında bir değer üretiyor. Bu durumda tür çıkarımı ile Int ürettiğini görüyoruz ve bunu uzunlukSeviyesi isimli val’a atıyoruz. Eğer if, else if ve else bloklarının gövdelerinin hepsi aynı türden bir değer üretmeseydi (örneğin else içinde 3 yerine “3” olsaydı), bu sefer tüm bloğun üreteceği değerin türü Int ve String’in ortak en yakın üst türü olan Any olacaktı. Kontrol ifadesi bu şekilde bir değer üretebildiği için, üretilen değer ile normalde herhangi bir değerle yapabildiğiniz tüm işlemleri yapabilirsiniz. Örnekte sonucu bir val’a atadık ama bunu bir metodun dönüş değeri olarak da belirleyebilir, başka bir metoda parametre olarak gönderebilir, kısacası bir değer ile yapabileceğiniz her şeyi yapabilirdik. 🙂

match … case İfadeleri

Scala’daki match … case ifadeleri, Java’daki ve başka bazı dillerdeki switch … case ifadelerine karşılık gelir ama onlardan çok daha fazla yeteneğe sahiptir. Hatta bir makalede “switch-case’in steroidli (daha güçlü) hali” şeklinde bir tanıma rastlamıştım. 🙂 match … case ifadeleri bir değeri farklı birçok durum ile karşılaştırır ve eşleşen case’in gövdesini çalıştırır. Tıpkı if gibi, match … case de değer üretir. Şimdi bir önceki örnekten devam ederek neler yapabildiğini görelim.
Java


String metin = "merhaba";
int uzunlukSeviyesi = metin.length < 2 ? 1 : (metin.length < 4 ? 2 : 3);
switch (uzunlukSeviyesi) {
case 1:
System.out.println("Çok kısa");
break;
case 2:
System.out.println("Kısa");
break;
default:
System.out.println("Çok kısa");
}

Scala


val metin = "merhaba"
val uzunlukSeviyesi = if (metin.length < 2) 1 else if (metin.length < 4) 2 else 3
uzunlukSeviyesi match {
case 1 => println("Çok kısa")
case 2 => println("Kısa")
// Yukarıdaki hiçbir case uygun değildi, varsayılan case
case _ => println("Uzun")
}
// Veya koşulları case ifadelerine yerleştirmek istersek if'i kullanabiliriz.
metin match {
// Sıra önemli, önce bu case çalışacak.
// Ayrıca if'ten sonra parantez kullanmak zorunda değilsiniz.
// Burada m için tür çıkarımı yapılacak, "metin" üzerinde match yapıldığı için m bir String olacak.
case m if m.length < 4 => {
println("Kısa")
}
case m: String if m.length < 2 =>
// match … case ifadelerinde süslü parantez kullanmak zorunda değilsiniz.
println("Çok kısa")
case _ => println("Uzun")
}
// Veya doğrudan metni karşılaştıralım ve cevap için değer üretelim.
val metin2 = "slm"
val cevap = metin2 match {
case "selam" => "Ve aleykümselam."
case "merhaba" => "Sana da merhaba."
// Bu bir MatchError
}
val cevap2 = metin2 match {
// Artık birden fazla durumu eşleştirebiliyoruz.
case "selam" | "slm" => "Ve aleykümselam."
case "merhaba" => "Sana da merhaba."
// Anlamadığımız için söyleneni aynen iade ediyoruz. 🙂
case _ => metin2
}

Java’daki switch … case kullanımını görüyorsunuz.  Şimdi Scala’daki haline bakalım.

2. satırdaki if ifadesinin tek satıra sadeleştirildiğini görüyorsunuz. Java’daki halini de tek satır haline getirdim ama aralarında ciddi bir anlaşılırlık farkı var. 🙂

4. satırda başlayan blok Java’daki switch … case ifadesinin birebir karşılığı ve uzunlukSeviyesi değeri üzerinde bir eşleştirme yapılıyor. Söz dizimindeki farklılıkları görüyorsunuz. match kelimesi eşleştirilecek değerden sonra geliyor, her case’ten sonra => (eşittir ve büyüktür) işareti geliyor, break kelimesi yok ve default kelimesi yerine değeri _ ile boş bırakılmış başka bir case var. Burada tıpkı Java’daki gibi case’lerin gövdelerini yazarken süslü paranteze ihtiyaç duymuyoruz. Okunabilirliği artırmak için kullanabilirsiniz de. Size kalmış. 🙂

12. satırda başlayan blokta eşleştirmeyi doğrudan metin değeri üzerinde yapıyoruz. Bu sefer yazdığımız case’lerimizde tanımlanan eşleştirmelere ek olarak koşullar da var. Eşleştirilen değeri farklı bir isimle kullanabiliyorsunuz. Bu vereceğiniz isim sadece o case’in gövdesinde tanımlı oluyor. Şu anda mantıklı gelmese de match … case ile ilgili daha gelişmiş konuları anlattığımda bunun aslında önemli bir özellik olduğunu göreceğiz. Diğer detayları koddaki yorum satırlarına yazdım o yüzden atlıyorum. Burada case’in gövdesini süslü parantezler içine yazabileceğimizi de görüyorsunuz.

28. satırda başlayan blokta türü String olan bir değeri doğrudan eşleştirmeye çalıştığımızı görüyorsunuz. Burada yazdığımız case’ler yetersiz kaldığı için eşleştirme yapılamayacak ve bir MatchError hatası alacağız.

35. satırda başlayan blokta ise yukarıdaki sorunu çözüyoruz ve match … case ifadesinden bir değer üretiyoruz. İlk case’te gördüğünüz gibi birden fazla değer ile eşleştirme yapılıyor. Bu değerler birbirinden | (dik çizgi) işareti ile ayrılıyor. Ayrıca olası bir MatchError’ı önlemek için varsayılan bir case de ekledik. Burada tüm case’lerden String türünde değerler üretildiği için match … case ifadesinin tamamının değeri, ve dolayısıyla cevap2, String türünde olacak.

Scala’daki match … case ifadeleri ile birçok şey yapılabildiğini ve Java’daki switch … case ifadelerinden daha güçlü olduğunu görüyorsunuz. Hatta yapabildikleri bunlarla da sınırlı değil. İleride ayrıca anlatacağım pattern matching denilen işlemi de match … case ifadeleri ile yazıyoruz ve bu oldukça güçlü bir araç.

Sonuç

Bu yazımda koşul ifadelerini ve bunların Scala’daki davranışlarını, diğer dillerdeki hallerine göre üstünlüklerini ve kullanışlılıklarını anlatmaya çalıştım. İnşallah faydalı olmuştur.

Görüşmek üzere. Hoşça kalın!