Scala’da Trait

Merhabalar!

Bu yazımda sizlere birkaç örnekle Scala’daki trait yapısından bahsedeceğim.

İşe IDEA ile TraitVeCaseClass isimli bir Scala projesi oluşturarak başladım. com.mehmetakiftutuncu.traitvecaseclass paket yapısını oluşturdum. Son olarak içinde boş bir main metodu olan Main.scala dosyasını oluşturdum.

Haydi başlayalım!

Scala’da Trait

Scala’daki trait’leri Java’daki interface‘ler ve abstract class‘ların birleştirilmiş haline benzetebiliriz. Bir trait sadece bazı değer ve metodları tanımlamak için kullanılabileceği gibi, bu değer ve metodların işlenişlerini de içerebilir. Kelime olarak özellik anlamına gelen trait çoğunlukla bir sınıfa veya objeye bir özellik kazandırmak için kullanılır. Bunlar örneklerle daha iyi anlaşılır sanırım. 🙂

Şimdi birkaç trait tanımlayalım ve bunları kullanalım.

Screenshot 2016-01-24 11.01.02.png

Gördüğünüz gibi trait’leri de tıpkı class veya object tanımlar gibi tanımlıyoruz ve trait özel kelimesini kullanıyoruz. Bu örnekteki trait’leri Traitler.scala dosyasına, bunları kullanan class’ları da Classlar.scala dosyasına yazdım.

Insan trait’i insana ait bir özelliği tanımlıyor ve gördüğünüz gibi sadece tanımlıyor, bir değer belirlemiyor. Bu yüzden bu değer daha sonra Insan trait’ini kullananlar tarafından tanımlanmak zorunda.

Muzisyen trait’i de enstrüman çalan bir insana ait özellikler tanımlıyor. Insan trait’inden türediğini (extends Insan) görüyorsunuz. Insan‘da olduğu gibi tanımlanan ama değer verilmeyen enstrumanAdi ve tecrube şeklinde 2 özelliği var. Bir de cal() adında metodu var fakat bu metodun gövdesi de tanımlanmış. Yani Muzisyen trait’ini kullanan hangi müzisyen olursa olsun, nasıl çalması gerektiğini bilecek.

Burada cal() metodu içindeki String kullanımını kısaca anlatmak istiyorum. Buna String interpolation deniyor. Başında s karakteri olan String’ler içine doğrudan değerler gömebiliyorsunuz. Bir değeri String içine gömmek için başına $ (dolar işareti) koymanız yeterli. Eğer ayrıca hesaplanması gereken bir değer varsa bunu ${} (dolar işareti ve ona bitişik açılan ve kapanan süslü parantezler) içine yazmanız gerekiyor. Küçük bir örnek:

val isim = "Akif"
val metin = s"Adım: $isim, büyük harflerle: ${isim.toUpperCase}"
// Sonuç => Adım: Akif, büyük harflerle: AKIF

İşleri çok kolaylaştırdığı kesin. Şimdi devam edelim. 🙂

Gitarist trait’i gitar çalan bir müzisyeni temsil edeceği için Muzisyen trait’inden türüyor ve enstrumanAdi özelliğine bir değer atıyor. Bir üst türde tanımlanan bir değeri veya metodu ezip değerini değiştirirken override kelimesini kullanıyoruz.

Virtuoz trait’i çaldığı enstümanda uzun yıllar tecrübe sahibi olup virtüöz sıfatına sahip bir müzisyeni temsil edeceği için Muzisyen trait’inden türüyor ve tecrube değerini 20 yıl olarak belirliyor.

Son olarak, Muhendis trait’i bir mühendislik alanı ve sorun çözecek bir metod tanımlıyor.

Burada gördüğünüz gibi trait’ler de tür kalıtımı (inheritance) yapabiliyor ve birbirlerinden türeyebiliyorlar.

Şimdi class’lara bakalım.

Ahmet sırasıyla GitaristMuzisyen ve Insan trait’lerinden türediği için 1 yıllık tecrübesi olan bir gitaristi temsil ediyor. Bu aynı zamanda Ahmet class’ından oluşturulmuş bir nesnenin tür olarak bir Gitarist, bir Muzisyen ve bir Insan olduğu anlamına geliyor.

Mehmet için durum biraz daha farklı. Mehmet aynı anda birden fazla türden türüyor. Buna çoklu kalıtım (multiple inheritance) da deniyor. Java bunu desteklemiyor. Java’da her sınıf yalnızca bir türden türeyebilirken Scala trait’ler ile bu sorunu çözmüş durumda. Trait’lerin en sık kullanılma nedenlerinden biri de bu. 🙂 Birden fazla türden türetirken önce extends kelimesini, sonraki her tür için with kelimesini kullandığımıza dikkat edin. Şimdi devam edelim. Mehmet bir gitarist ama aynı zamanda bir Virtuoz. Bu da Mehmet‘e önce Gitarist‘ten gelen tüm özelliklerin eklendiği anlamına geliyor. Sonra bunun üzerine Virtuoz ekleniyor ve Mehmet‘in tecrube özelliğine değer atanıyor. Bu değer önceden tanımlı olsaydı bile ezilecekti ve Virtuoz trait’inin belirlediği değer ile değişecekti.

Ali ise hem 5 yıldır piyano çalan bir müzisyen, hem de bilgisayar mühendisi. Muhendis trait’inde tanımlanmış olan sorunuCoz() metodunu implement ettiğini görüyorsunuz.

Trait’lerimizi ve sınıflarımızı tanıdığımıza göre Main.scala içine bunları kullandığımız örnekler yazalım.

Screenshot 2016-01-24 11.37.09

Gördüğünüz gibi karakterlerimiz kendilerine kazandırdığımız özellikleri sergiliyorlar. 🙂

Sonuç

Bu yazımda sizlere Scala’daki trait yapısından, string interpolation’dan ve multiple inheritance’tan bahsetmeye çalıştım. Asıl amacım bu yazıda case class’lardan da bahsetmekti ama yazı uzadıkça uzadı. Case class için de anlatılacak çok şey olduğundan onu bir sonraki yazımda anlatmaya karar verdim. Bu kararı sonradan aldığım için de yazı için oluşturduğum projenin adını değiştirmedim. Sonraki yazımda aynı proje üzerinden devam edeceğim. Anlayışınıza sığınıyorum. 🙂

Projeye Github’daki depomdan ulaşabilirsiniz. https://github.com/mehmetakiftutuncu/ScalaBlogOrnekleri/tree/master/TraitVeCaseClass

Bir sonraki yazıda görüşmek üzere.

Hoşça kalın!

Scala’da Değişkenler (var), Değerler (val) ve Metodlar (def)

Merhabalar! Bundan sonraki yazılarımda daha çok ve somut örnekler ve karşılaştırmalar üzerinden giderek temel birçok kavrama değineceğim. Böylece Scala ile daha çok ve anlamlı uygulamalar geliştirmeye başlayabileceğiz. Bu yazımda en programlamadaki en temel kavramlardan biri olan değişkenlerden, Scala’da daha sık kullanılan değişmez değerlerden ve metodlardan bahsedeceğim.

Haydi başlayalım!

1. Değerler (val) ve Değişkenler (var)

Uygulama geliştirirken bir değeri veya nesneyi saklamak ve isimlendirmek için değişkenler kullanırız. Hatta bazen bu isimlendirdiğimiz şeyin bir daha değiştirilmemesini de isteyebiliriz. Scala’da bu işler için 2 özel kelime var.

1.1. Değişken (var)

Değerini sonradan değiştirebileceğiniz bir değer veya nesne oluşturmak için var özel kelimesini (İngilizce değişken anlamına gelen variable‘ın kısa hali) kullanabilirsiniz. Aşağıdaki birkaç değişik örnek yazdım.

İlk satırda sayi adında Int türünde, değeri 6 olan bir değişken oluşturuyoruz. Burası açık.

İkinci satırda adı metin olan, türünü belirtmediğimiz bir değişken yaratıyoruz. Böylece Scala String olduğunu çıkarım yaparak bulacak.

Üçüncü satırda ise yarattığımızda değerini belirtmediğimiz ciftMi adında Boolean türünde bir değişken oluşturuyoruz. Bir değişkeni değerini vermeden yaratmak için Java’da ve diğer dillerde sadece adını ve türünü yazmak yeterliyken, Scala’da değerinin sonradan verileceğini belirtmemiz gerekiyor. Bunu da _ (alt tire) yer tutucu (placeholder) karakteri ile sağlıyoruz. Değerini vermeden değişken yaratacağımız zaman – Scala değeri bilmeden tür çıkarımı yapamayacağı için – türü belirtmemiz gerekiyor. Değerini belirtmeden değişken yarattığımızda aslında o değişkene belirttiğimiz türe göre değişecek varsayılan bir değer atanıyor. Bu varsayılan değer sayı türleri için 0, Boolean için false, bunlar dışındaki referans türleri için de null. O yüzden 6. satırda ciftMi değişkeninin değeri olarak ekrana false yazılacak. ciftMi değişkeninin değerinin sonradan değiştirilebildiğini görüyorsunuz.

var ile ilgili bir not; eğer Scala’yı önerildiği gibi, fonksiyonel programlamaya uygun kullanmak istiyorsanız hiç var kullanmamaya çalışın. İleride değişmezlik (immutability) hakkında yazacağım yazı(lar)da bu konuya tekrar değineceğim. 🙂

1.2. Değer (val)

Değerini sonradan değiştiremeyeceğimiz bir değer veya nesne oluşturmak için val özel kelimesini (İngilizce değer anlamına gelen value‘nun kısa hali) kullanabiliriz. val ile değerler yaratmak Java’da ve başka bazı dillerde değişken tanımının önüne final özel kelimesini getirmeye eşdeğerdir. Bir kere oluşturulur, değeri sabittir, yeniden atama yapılamaz. var için olana benzer bir örnek yapalım.

Burada da aynı şekilde bir Int ve String oluşturuyoruz yalnız bu sefer bu değerlere yeniden atama yaparak sakladıkları değerleri değiştiremeyeceğiz.

4. satırda gördüğünüz gibi val ile oluşturulmuş bir değerin saklayacağı değeri belirtmeden geçemiyorsunuz çünkü o val bir kere oluşturulduktan sonra değerinin değiştirilmesi engellenecek, sonradan değer ataması yapılamayacak.

7. satırdaki işlem de hata verecek çünkü daha önceden tanımlanmış bir val’ın sakladığı değerin yerine başka bir değer atamaya çalışıyoruz.

var ile ilgili yazdığım notu tamamlayayım; değişmezliği sağlayabilmek için var değil val kullanmaya çalışın. 🙂

2. Metodlar (def)

Aslında daha önceki yazılarımdaki örneklerde metodları kullanmıştık. Scala’da metodlar def özel kelimesi ile tanımlanırlar. Hemen birkaç örnek görelim.

Yukarıdaki örnekte birçok değişik metod tanımlaması görüyorsunuz. İlk 4 metod tanımlaması da aslında bir işlem yapmayan, Unit dönüş türüne sahip, gövdesi boş metodlar. Ama tanımlanışlarında farklılıklar var.

İlk metod hiç parametre tanımlamıyor. Şimdiye kadar gördüklerimiz aksine dönüş türü de belirtmiyor. Gövdesinin boş olduğunu görüyorsunuz, yani bir iş yapmıyor, yani aslında dönüş türünün Unit olması gerekirdi. Scala’da Unit dönüş türüne sahip metodları tanımlarken = (eşittir) işaretini ve dönüş türünü birlikte atlayabiliyoruz.

İkinci metod da aslında ilk metod ile birebir aynı. Parametre almıyor ve dönüş türü Unit. Yalnız bu sefer = kullandığımız için Scala tür çıkarımı yapıyor. Gövde boş olduğu için de (aslında Unit döndüren bir şeylerle dolu da olabilirdi) metodun dönüş türünün Unit olduğuna karar veriyor.

Üçüncü metod da ikinci metod ile aynı. Bu sefer dönüş türünü kendimiz belirttik.

Dördüncü metodda diğer üç metoddan farklı bir nokta var. Bu metod aslında diğerleri gibi parametresiz bir metod değil. Parametre alacak şekilde ama parametresi olmadan tanımlanmış. Scala’da parametresiz tanımlanmış bir metodu parantezlerle, parametre alacak bir metodu da parantezleri olmadan çağırmaya kalkarsak hata alıyoruz. 6. ve 7. satırlarda bu metodları çağırma sırasındaki farkı görüyorsunuz.

9. satırdan itibaren tanımladığımız metodlar (tür çıkarımı ile) geriye Int döndüren metodlar.

sayi ve sayi2() metodları arasında buBirMetod ve veHattaBuDa() metodlarının arasındaki ilişkinin aynısı var. Sonraki satırlarda farklı şekillerde çağırıldıklarını görüyorsunuz.

topla metodu 2 tane Int parametresi olan bir metod. Belki de buradaki en anlaşılır metod. 🙂

carp metodunda ilginç bir farklılık var. Bu metodun 2 tane parametre grubu var. Scala’da metodların birden fazla parametre grupları olabiliyor. Ayrı parantezler halinde yazılıyorlar ve metodun imzasına dahil ediliyorlar. Buradaki metod carp(Int)(Int): Int şeklinde bir imzaya sahip. Metodun nasıl çağrıldığını 21. satırda görüyorsunuz.

karistir() metodu şimdiye kadar tanımladıklarımızı kullanıp bazı hesaplamalar yapan bir metod. Bu metod da veHattaBuDa() metodu gibi parametre alacak şekilde ama parametresi olmadan tanımlanmış. Gövdesinde birden fazla ifade olacağı için süslü parantezler {} kullanılıyor. Son olarak, gövdesindeki son ifadenin değerini geri döndürüyor (tür çıkarımı da buna göre yapılıyor).

Scala’da metodlar, Java’daki gibi sadece bir class içinde değil, başka yerlerde de tanımlanabiliyor, örneğin başka bir metodun içinde. 🙂 Bunun bir örneğini görelim.

Burada ben metodunun beni metodunun içinde tanımlandığını görüyorsunuz. Scala’da bu mümkün. Bir metodun içinde tanımlanan başka bir metod, sadece tanımlandığı metodun gövdesi içinde ulaşılabilir durumdadır. Yukarıdaki örnekte 10. satırda ben metodu bulunamadığı için hata alınacak.

Metodlarla ilgili değinmek istediğim son bir konu var. Scala’da parametreleri olan metodları çağırırken, bu parametreleri isimlerini de kullanarak gönderebilirsiniz. Yapmanız gereken parametrenin değerinin önüne adını yazmak ve = (eşittir) atama işaretini koymak. Bu özelliği kullanarak parametre listesini birebir takip etmeden bile metodunuzu çağırabilirsiniz. Bunun da örneklerini görelim.

Bu örnekte tanit adında, 4 tane parametresi olan, Unit döndüren bir metod tanımlıyoruz. Burada cinsiyet metoduyla, yukarıda bahsettiğim metod içinde başka bir metod tanımlamanın bir örneğini daha görüyorsunuz. Gönderilen erkekMi parametresinin değerine göre kişinin cinsiyetine karar verecek küçük yardımcı bir metod. Bu metodun gövdesinde karar vermeye yarayan if özel kelimesi var. Bundan sonraki yazılarımda daha detaylı bahsedeceğim. Şimdi 16. satırdan itibaren metodun farklı şekillerde çağrılışlarını inceleyelim.

16. satırda şimdiye kadar bildiğimiz yöntemle, sırayla parametreleri vererek çağırıyoruz.

17. satırda birer birer bütün parametrelerin isimlerini de vererek çağırıyoruz. Gördüğünüz gibi bu yöntem kodun okunduğunda daha kolay anlaşılmasına yardımcı oluyor. Tabi bunun için metodu tanımlarken parametrelere anlamlı isimler vermek gerekiyor.

18. satırda parametrelerin hepsine değil, sadece bazılarına isimlerini de vererek değer gönderiyoruz. Bu yine bazı durumlarda kodun anlaşılabilirliğini artırmak için güzel bir yöntem. Özellikle türü Boolean olan parametrelerin değerlerini verirken isimleriyle çağırmanızı tavsiye ederim. Burada hala parametreleri gerçek sıralarıyla çağırdığımıza dikkat edin.

19. satırda işler biraz daha değişiyor. Artık parametreleri kendi istediğimiz sırada gönderiyoruz. Tüm parametreleri tanımladığımız için ve hepsini ismiyle gönderdiğimiz için Scala metod çağrılarını bu şekilde yapmamıza bile izin veriyor.

Ekleme: Metod Parametrelerinde Varsayılan Değerler

Yazıyı yazıp yayımladıktan sonra atladığımı fark ettiğim için eklemek istediğim, metodlar yazarken sıkça kullanılan bir konu daha var. Scala’da metodların parametrelerine varsayılan değerler belirleyebilirsiniz. Böylece metodu çağırırken varsayılan değeri olan bir parametreyi yazmadan da geçebilirsiniz. Böyle durumlarda metod tanımlanırken belirtilen varsayılan değer kullanılır. Bir örnek ile görelim.

Bir önceki örnekteki metoda sadeceAdiKullan adında bir Boolean parametre daha ekledim. Bu parametrenin varsayılan bir değeri var, false. Ve metodun işleyişi bu parametrenin değerine göre değişiyor. 20 ve 21. satırlarda gördüğünüz gibi sadeceAdiKullan parametresini hiç dahil etmeden de metodu çağırabiliyoruz. Bu durumda bu parametrenin değeri varsayılan değer olan belirtilen değer oluyor. Ama 24, 25 ve 26. satırlardaki kullanımda sadeceAdiKullan parametresini de işin içine katıyoruz ve istediğimiz değeri belirtiyoruz.

Bu eklemeyle beraber metod parametrelerini isimleriyle kullanma konusunda bir tavsiyede bulunayım. Metodun parametrelerini gönderirken okunurluğu artırmak adına parametreleri, özellike de türü Boolean olan parametreleri, isimlerini kullanarak gönderin. Yukarıdaki örnekte 21. ve 26. satırdaki kullanımlar buna örnekler. 🙂

Sonuç

Bu yazımda programlamadaki temel kavramlardan değişken, sabit değer ve metodları ve bunların Scala’daki kullanılışlarını anlatmaya çalıştım. İnşallah anlaşılır olmuştur.

Kaynak

Yunus Emre’nin Severim Ben Seni Candan İçeri şiiri: http://www.yunusemre.gov.tr/index.php/eserleri/siirleri/siirlerin-devami/severim-ben-seni-candan-iceri

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