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!

Reklamlar

Scala’da Class ve Object

Herkese merhabalar!

Bu yazımda sizlere Scala’daki class ve object yapılarını, aralarındaki farkları ve bunların Java’dan farklarını anlatmaya çalışacağım. Bir önceki yazımda IDEA ile geliştirme yapmaktan bahsettiğim için artık yazılarımı projeler halinde IDEA üzerinde geliştireceğim. Ayrıca bu projeleri Github’daki https://github.com/mehmetakiftutuncu/ScalaBlogOrnekleri depoma ekleyeceğim.

Başlamadan önce IDEA ile ClassVeObject isimli bir Scala projesi yarattım. com.mehmetakiftutuncu.classveobject 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 Class

Scala’da class tıpkı Java’daki gibi bir sınıfı ve o sınıfın türünü temsil eder. class özel kelimesi ile oluşturulur. Java’dan farklı olarak içine yazılacağı dosya ile aynı isme sahip olması şart değildir. Ayrıca bir Scala dosyası içine en dışarıda sadece tek bir class yazmak da şart değildir. Bir Scala dosyası içinde birden çok class (hatta object ve trait) yazılabilir.

Şimdi Java ile karşılaştırmalı bir örnek yapalım. Burada bahsettiğim dosyaları isimlerine tıklayarak Github deposunda görüntüleyebilirsiniz.

JavaSinifi1.java dosyasına bir Java sınıfı, ScalaSinifi1.scala dosyasına da onun Scala’daki birebir karşılığını yazdım. Bu örnek aynı zamanda projenizde Scala ile birlikte Java da kullanabileceğinizi gösteriyor. 🙂 Şimdi ScalaSinifi1 sınıfını inceleyelim.

Screenshot 2016-01-05 21.29.09

Buradaki ilk fark, public olan JavaSinifi1 sınıfının aynısı olan ScalaSinifi1 sınıfının tanımında public kelimesinin olmaması. Bunun basit bir nedeni var. Scala’da aksi söylenmedikçe her şey public olarak tanımlanır. Scala’nın gereksiz kelimeleri atmasına bir örnek daha. 🙂

Daha sonra iki class da birer private field (örnek değişkeni) tanımlıyor.  JavaSinifi1 bu field’ın ilk değerini varsayılan (boş) constructor (yapılandırıcı) metodunda atıyor. ScalaSinifi1 sınıfında ise durum biraz daha farklı. Scala’da bir class’ın gövdesinde metod haricindeki her şey aslında o class’ın varsayılan constructor’ını oluşturuyor. Yani ScalaSinifi1.scala dosyasındaki 7. satır aslında bu sınıfın varsayılan constructer’ında. Bu yüzden isim field’ının ilk değerini doğrudan atıyoruz. Ayrıca burada isim field’ının private olmasını özellikle belirttiğimizi görüyorsunuz.

Gelelim parametre alan ek constructor’a. Java’da sınıfın adına sahip bir metod gibi tanımladığımız ek constructor’ı, Scala’da sınıfın adı yerine this adıyla tanımlıyoruz. Scala’daki ek constructor’ların şöyle bir farkı var. Her ek constructor ilk önce this() diyerek varsayılan constructor’ı çağırmak zorunda. Yoksa hata alırsınız. Bu örnekte de isim field’ına önce boş bir String, sonra da constructor’a gönderilen değer atanıyor.

Buradaki ScalaSinifi1 sınıfını Java’daki örnekle birebir eşleşmesi için kasıtlı olarak böyle yazdım. Şimdi başka bir örnekle Scala’ya daha uygun ve daha iyi nasıl yazabileceğimizi görelim.

Screenshot 2016-01-05 22.18.01

Burada JavaSinifi2.java ile birebir aynı olan ScalaSinifi2.scala sınıfını görebilirsiniz. Gördüğünüz gibi Scala hali çok daha kısa ve basit.

Scala’da class’a ait public field’ları birer metod parametresi yazıyormuş gibi parantezler içine yazabiliyoruz. Bununla birlikte varsayılan değer atamalarını da kullanınca basit bir class tanımı tek satıra bile indirgenebiliyor. Aynı şeyi Java’da yapmak için fazladan 2 constructor yazmak zorunda kaldığımıza dikkat edin. 🙂

Son bir not olarak; bu sınıfların içinde birer de metod olsun istedim ve toString metodlarını tanımladım. Java’da @Override işaretlemesini kullanmamız gerekiyorken Scala’da override özel kelimesini kullanıyoruz.

Scala’da Object

Yazılım geliştirirken sık sık ihtiyaç duyduğumuz singleton pattern denilen bir kavram var. Bir nesneden bellekte sadece bir örnek olmasını sağlıyor. Java’da bunu sağlamak için singleton olmasını istediğimiz class’ın dışarıdan erişilebilen hiçbir constructor’ı olmaması, static şekilde tanımlanmış kendi türünden bir field’ı olması ve bu field’ı gerektiğinde geri döndüren dışarıya açık bir metodunun olması gerekiyor. Scala’da singleton yazmak istediğimizde tek bir kelime kullanmamız yeterli; object. 🙂 Scala’daki object kelimesi ile tıpkı bir class tanımlar gibi singleton’lar tanımlayabiliyoruz. Bir örnekle görelim.

Screenshot 2016-01-05 22.32.56

Burada JavaSingleton.java ile ScalaSingleton.scala arasındaki farkı görebiliyorsunuz. ScalaSingleton denilen tür, tanımı gereği bir singleton ve bellekte sadece bir örneği olacak. Object içinde tanımlanan metodlar, singleton class’a ait normal metodlar veya herhangi bir class’a ait static metodlar gibi çalışıyor. Yani, Main.scala içindeki örnekte de görebileceğiniz gibi, sınıfın bir örneği yerine doğrudan sınıfın adı üzerinden çağrılabiliyor.

Scala’da Companion (Yardımcı) Object

Object ile yapabileceğiniz tek şey kolayca singleton oluşturmak değil. Eğer class’ınızla aynı isimde bir de object’iniz varsa bu object o class’ın companion (yardımcı) object‘i oluyor. Eğer bir class’ın companion object’i varsa o tür için hem class’ın hem de object’in özelliklerini kullanabilmeye başlıyorsunuz. Bir örnek üzerinden görelim.

Screenshot 2016-01-05 23.07.39

JavaDunyasi.java dosyasında static tanımlanmış sabit dunyaAdi, static olmayan sabit surum, sürümü 1 olarak belirleyen varsayılan constructor, sürümü dışarıdan alan ek constructor, static tanımlanmış selam() metodu ve toString tanımlamasını görüyoruz. Şimdi Scala tarafına gelelim.

ScalaDunyasi.scala dosyasında bir önceki örnekteki gibi bir class tanımlaması görüyoruz. 6, 7 ve 8. satırlar bize surum sabitini, ek constructor’a olan ihtiyacı ve toString tanımlamasını sağlıyor. Şimdi sonrasında yazdığımız companion object’i inceleyelim.

11. satırda val olarak tanımladığımız için sabit olan, bir object içinde tanımladığımız için de static olan dunyaAdi değerini görüyoruz. Bu değere 7. satırda static olarak erişildiğine dikkat edin.

13 ve 17. satırlarda tanımlanan metodlar özel isimli metodlar. Scala’da bir tür adından sonra açılan ve kapanan parantezler () yazmak aslında o türün companion object’indeki apply metodunu çağırmak demek. Burada işte bu özellikten faydalanarak kendimize ek constructor’lar yazdık. Dikkat ederseniz tanımladığımız apply() metodları bizim tanımladığımız ScalaDunyasi türünden değerler döndürüyorlar. Ayrıca Main.scala içindeki 33 ve 34. satırlara dikkat ederseniz apply() metodları sayesinde yeni bir nesne oluştururken new kelimesini de kullanmak zorunda kalmadık. Aslında yaptığımız şey ScalaDunyasi object’indeki apply() metodunu çağırmak. Bu metodların gövdelerinde de yeni birer ScalaDunyasi nesnesi oluşturuyoruz. Böylece bu metodlar constructor gibi çalışıyorlar.

22. satırda da selam() metodunu görüyoruz. Bu metod bir önceki singleton örneğimizdekiyle aynı mantıkta çalışıyor.

Gördüğünüz gibi class’ı ve object’i bir arada kullanarak daha az kodla daha gelişmiş işler yapabiliyoruz. Unutmayın, bir object’in companion object olabilmesi için class’ı ile aynı isimde olması gerekiyor. Ayrıca ScalaDunyasi.scala dosyasında bir dosya içinde birden fazla class ve/veya object yazılabileceğinin de örneğini görmüş olduk. 🙂

Sonuç

Bu yazımda sizlere Scala’nın class ve object yapılarını, companion object’i ve bunların Java’daki hallerinden farklarını örneklerle anlatmaya çalıştım. Tüm terimleri Türkçeleştir(e)medim çünkü o zaman yazdıklarım çok daha anlaşılmaz bir hal alıyor. 🙂

Bu yazıdaki projeyi Github’daki https://github.com/mehmetakiftutuncu/ScalaBlogOrnekleri depomda bulabilirsiniz.

İnşallah anlaşılır olmuştur. Sonraki yazılarda görüşmek üzere.

Hoşça kalın!