Bu Sayfayı Paylaş:

Kavram

Scala

Tanım: JVM üzerinde çalışan hem fonksiyonel hem de nesne yönelimli bir programlama dili

Alıntı

Scala Programlama Dili

Scala hibrit bir dildir ve JVM üzerinde çalışır. Java standart kütüphanesindeki sınıfları ve bilinen tüm Java kütüphanelerini direkt olarak kullanabilir
Sahipleri : Yusuf Boyacıgil
Bu yazı izinle alıntılanmıştır : http://yboyacigil.com/turkish/scala/scala-language/
Zamanında bir kitap okumuştum. İsmi: Pragmatic Programmer. Kapağı da ilginçti. Marangozluktan biraz anlayan bilir kapağında bir rende resmi var. Benim babam marangozdu ben de onun yanında zamanında çıraklık yaptım. Bu resim kanımca programlama bir zanaattır mantığıyla konmuştur ve hakikaten de öyledir. Sanattır diyeni de vardır ama bana göre sanattan çok zanaattır o başka. Herkes babasının oğludur. Ben de bir nevi marangoz gibi zanaatkar insanım, öyle görüyorum kendimi. O bakımdan kitabın kapağıyla da o taraflara yapığı gönderme ayrıyeten anlamlıdır benim için.
Bu kitapta şöyle bir ögüt vardı: “Her sene yeni bir programlama dili öğren!”. Nitekim o öğütü tuttum ve o günden sonra yeni dilleri öğrenmeye çalıştım. Python, erlang, javascript, ruby, smalltalk dillerini çalıştım. Öğrendiğim kadar da unutmuşluğum vardır. Ama yeni bir dile çalışmaya başlayınca programlamaya bakışın, problemlere çözümde yaklaşımın gelişiyor. Aradaki farkları, benzerlikleri görüyorsun; daha yukarıdan bakabiliyorsun. Bu dillerin bir de kendine ait felsefeleri var; anlamaya çalışıyorsun oradan yeni şeyler kapıyorsun. Kesinlikle tavsiye ediyorum herkese. Şöyle bir geçmişe dönüp bakınca bak .net’e (döt net) neden ilgi duymamışım diye de kendime soruyorum şimdi?!! Microsoft’a zamanında gıcıklığımızdan (bugün bunun çok da anlamlı olmadığını anlıyorum) belki uzak kaldım micro$oft’un sunduklarına.
Yeni bir programlama dili öğrenmek kolaydır aslında. İki haftada alışır birşeyler yapamaya muktedir olursun. Ama o dile tam anlamıyla hakim olmak bir seneni alır. O yüzden yavaş yavaş bıkmadan usanmadan; acele etmeden ağır ağır gideceksin. Scala çalışıyorum. Bu seneki dilim bu.
Scala hibrit bir dil. Hibrit? Yani hem fonksiyonel hem de nesneye dönelik yani yönelik :) Scala’nın daha ilginç yanı kendi derleyicisi var ama Java byte-code üretiyor. Yani JVM üzerinde çalışıyor. Java standart kütüphanesindeki sınıfları ve bilinen tüm Java kütüphanelerini direkt olarak kullanabiliyorsun. Yanında kendi kütüphanesi de var. Kendi kütüphanesi olması gerektiği gibi Java kütüphanesini tamamlıyor onu tekrarlamıyor.
Bugün linkedin, twitter ve foursquare gibi startup’ların kendi geliştirmeleri için kullanıyor olmasıyla popüler de oldu. Bilinen programlama dilleri listesinde de çok kullanılmasına göre 34. sıraya kadar da yükselmiş ve yine JVM üzerinde geliştirilmiş kendinden eski başka dilleri (mesela: Clojure, Groovy) de geçmiş durumda. Bu açıdan bakıldığında da kötü bir seçim değil yani.
Son olarak Scala ile ilgili olarak fonksiyonel programalama dili olması ve Java’nın sevilmeyen açıklarını kapaması gibi iki konuya değinmek istiyorum.

Fonksiyonel Programlama


Fonksiyonel programlama aslında uzun zamandır var olan bir programlama stili ve son yıllarda daha çok konuşulmaya başladı. Matematikteki fonksiyon mantığının programlamaya uyarlanmasıdır aslında. Bu programlamanın doğasına da tam oturur. Program dediğin netice itibariyle bir girdiyi alıp onu işleyip bir çıktı üreten şeydir yani bir fonksiyondur. Bir programın tüm parçalarını bu şekilde ifade edebilirsin. Program dediğin bir fonksiyonlar bütünüdür. Scala ile pür fonksiyonel programlama yapmak mümkündür.
Fonksiyonel programlama deyince tabi literatürde geçen “high order functions”, “no state preservation”, “clojure functions” gibi konulara da ileride değiniriz.
Scala aynı zamanda nesneye yönelik programlama için de gerekli olan yapıları barındırır. Bu onu hibrit yapan özelliğidir. Java gibi nesnel programlamaya aşina birine de Scala bu özelliğiyle kapıyı açık tutsa da kanımca, Scala’nın mucitleri o kafadakileri de fonksiyonel programlamaya devşirmek istemiş olabilirler.

Java’daki Eksiklikler


Java’nın eksiklerini tamamlaması ile ilgili olarak da Java’da çokça şikayet edilen primitive tipleri ortadan kaldırmasıyla dikkate şayandır. Bu şunun için önemlidir: Scala’da herşey nesnedir yani primitive tip yoktur. Bu da primitive’i nesneye, nesneyi primitive dönüştürmek gibi ameli işleri ortadan kaldırdığı gibi aynı zamanda temizlik anlamında da hoştur.
Bir başka konu “operator overloading” diye bilinen C++’çıların Java’da en çok istediği ve belki bu yüzden de çokça eleştirdiği Java’da olmayan bu özelliği eklemiş olmalarıdır. Yani siz herhangi yarattığınız bir tip (sınıf/class) için mesela “+” operatörünü tanımlayabilirsiniz. Yalnız single-inheritance hala var ama o da aslında olmasının bir programlama diline hayır getirdiği oldukça tartışmalı bir konu zaten.
Java’da sıklıkla kullanılan anonymous class’ları da fonksiyonlara havale ederek daha az kod yazarak aynı işi yapabilmesi de bir anlamda sentaks olarak bir temizlik, kolaylık getiriyor.

Alıntı

Scala 'lazy val'

Scala’da değişken/argüman tanımlarken iki tane anahtar kelime var: var ve val
Sahipleri : Yusuf Boyacıgil
Bu yazı izinle alıntılanmıştır : http://yboyacigil.com/turkish/scala/scala-lazy-val/
Scala’da değişken/argüman tanımlarken iki tane anahtar kelime var: var ve val. İlki için söylecek çok bir şey yok. Değişken tanımlamak için var’ı kullanmak durumundasın. Ama ikincisi aynı Java’daki final gibi sadece ilk seferinde bir değer atanmasını istediklerini tanımlamaya yarıyor. İkinci defa bir atama yapamıyorsun; aslında program içerisinde böyle sadece bir kere atama yapmaktan ziyade val ile tanımladıkların daha çok sonradan değerinin değiştirilmesini istemediğin değişkenler içindir.
scala> var x = { println("x=1"); 1 }
x=1
x: Int = 1
scala>  lazy val y = { println("y=2"); 2 }
y: Int = <lazy>
scala> y
y=2
res0: Int = 2
var ve val'ı sadece değişkenleri tanımlarken değil aynı zamanda fonkisyon ve sınıf yapılandırıcıları (constructor) parametrelerini tanımlarken de kullanabilirsin. Bu durumda var ile tanımladığın parametreler fonksiyon ve yapılandırıcı içerisinde değiştirilebilirken, val ile tanımladıklarının sadece değerini okuyabilirsin.
Bunların yanında bir lazy val diye bir anahtar kelime daha var. Lazy isminden anlaşılabileceği veya programlamaya aşina olanlar için belli şimdi değil sonrayı çağrıştırıyor. Değişkenin değerini şimdi değil de sonra ata demek. Sonra ne zaman? İlk defa o değişkene kod çalışırken erişildiği zaman.
scala> abstract class A { val x: String 
     | println(x.length)
     | }
defined class A
scala> object B extends A { lazy val x = "Yusuf" } 
defined module B
scala> B
x len: 5
res2: B.type = B$@6a48ffbc
Yukarıda y değişkeni lazy val olarak tanımladık ve erişene kadar değer atamadığını görebiliyoruz. Yukarıdaki örneklerde atama yaparken { println("..."); ... } dikkatinizi çekmiştir. Scala’da kod blokları {...} arasında tanımlanır ve atama yaparken de bir kod bloğu kullanabilirsiniz.
val diye tanımladığımız değişkenler kod çalışırken en az bir kez yazılacak ve belki bir kere, on kere, yüz kere, bin kere okunacak belki de hiç okunmayacak(!). Madem okunmaya da bilir o zaman okunmayacak birşey okunana kadar atamazsak hafızayı daha az kullanmış oluruz. Onun için değişkeni lazy val ile tanımlayabiliriz. Bu yöntem hafıza kullanımı açısından faydalı olsa da cpu’yu normal bir atama gibi değil de daha fazla meşgul ediyor. Nedeni her erişimde en azından bir kez atama yapıldı mı yapılmadı mı diye kontrol etmek gerekiyor bir de ufak bir flag tutmak gerekir atandığını işaretlemek için. Bir de birden fazla thread bu değişkene erişebileceği için bu erişim kontrollü yapılması yani herhangi bir t anında sadece ve sadece bir thread’in erişmesi için gerekli senkronizasyonun işletilmesi gerekir.
Lazy’nin kullanılması gereken ilginç bir örnek vereyim:
scala> abstract class A { val x: String 
     | println("x len: " + x.length)
     | }
defined class A
scala> object B extends A { val x = "Yusuf" } 
defined module B
scala> B
java.lang.NullPointerException
at ...
B‘yi ilk kullanmaya çalıştığımızda NPE’yi yeriz. ;) Ama B‘yi şu şekilde tanımlarsak sorun olmaz:
scala> abstract class A { val x: String 
     | println(x.length)
     | }
defined class A
scala> object B extends A { lazy val x = "Yusuf" } 
defined module B
scala> B
x len: 5
res2: B.type = B$@6a48ffbc
Bunun nedeni A sınıfındaki x‘i B objesinde lazy olarak değiştirdik. Artık x‘e ilk erişildiğinde değeri atanacak. İlk erişildiği nokta ise A sınıfının başlangıcı (initialization’ı). İlk örnekte,x daha tanımlanmadığı için yani B objesi hafızada daha oluşturulmadan x‘e atama yapılmayacağı için null olarak kalacağından NPE oluşur.
Son olarak lazy’nin bir de döngüsel (cyclic) bağımlılıklarda nasıl işe yaradığını görelim ve macerayı tamamlayalım. Aşağıda birbirine bağımlı sınıf tanımları var:
object CyclicLazy extends App {
 
  trait A { val x: A }
  case class B extends A { val x = C() }
  case class C extends A { val x = B() }
  println(B().x)
}

B ve C sınıfları birbirine bağımlı. Bunların başlangıc kod bloklarında ki val x = ... kısmını lazy val x = ... şekline dönüştürmezsek StackOverflowError alırız. Lazy’yi bu örnekte olduğu gibi döngüsel bağımlılıklardan kaynaklanan durumları önlemek için de kullanabiliriz.

Alıntı

Scala Nil, Nothing, Null

Scala'da Nil, Nothing, Null İfadeleri ve Farkları
Sahipleri : Yusuf Boyacıgil
Herşey aşağıdaki gibi bir fonksiyon/metodu anlamaya çalışırken gelişti:
scala> def dup[T](x: T, n:Int): List[T] = if (n==0) Nil else x :: dup(x,n-1)
dup: [T](x: T, n: Int)List[T]
Burada herhangi tipteki nesneyi n kere çoğatıp sonunda o tipte bir liste üreten bir fonkisyon tanımı var.
scala> dup("yusuf", 2)
res31: List[java.lang.String] = List(yusuf, yusuf)
Yukarıda bu fonksiyonu String tipinde bir nesne ile çağırdığımız zaman elde ettiğimiz sonucu görüyoruz. ;)
Fonksiyon ne yapıyor? n 0 olana dek x‘i bir listenin başına ekliyor. :: listeler için tanımlı ve elm :: list şeklinde kullanılan ve elemanı listenin başına eklemek için tanımlı bir operatördür. Yani:
dup("yusuf", 2) -> "yusuf" :: dup("yusuf", 1)
dup("yusuf", 1) -> "yusuf" :: "yusuf" :: dup("yusuf", 0)
dup("yusuf", 0) -> "yusuf" :: "yusuf" :: Nil
En sondaki Nil‘e dikkat! Nil Java’cı biri için null‘sa haliyle bu NPE’ye neden olur diye düşündüm ilk olarak. Ama fonksiyon çalıştı. Nasıl? Demek ki Nil eşittir null doğru değil. Hadi diyelim Nil null değil. İyi de :: operatörü nasıl çalışıyor? O zaman type inference diye geçen, derleyicinin burada akıllı bir şekilde Nil’in boş bir liste olacağını anlayıp ona göre bir düzenleme yaptığı geldi aklıma. Ama o da değilmiş!
Scala API dokümanına bakınca, Nil’in boş bir List’e olduğunu gördüm:
object Nil extends List[Nothing] with Product with Serializable
Nothing?!! Nothing scala’da tanımlı tüm tiplerin alt tipiymiş. İyi de bu ne demek? Scala’da tüm tipler scala.Any tipinden geliyor. Java’daki java.lang.Object gibi. Any’nin iki direkt alt tipi var biri scala.AnyVal diğeri scala.AnyRef. İlki Java’daki int, double, float gibi sabit bir değer içeren tipleri, ikincisi de geri kalan diğer tüm tipleri ifade ediyor. Nothing‘in Any’den gelen diğer tüm tiplerin bir alt tipi olması demek Nothing herhangi tipe referans olarak kullanılabilir demek. Ne var ki Nothing tipinde bir nesne yaratmazsınız. Hiç/hiçlik bilinir ama gösterilemez yani ;)
List[Nothing] de bu durumda herhangi bir tipteki boş liste demektir. Çünkü hem Nothing tüm tiplerin alt tipidir hem de Nothing tipinde bir nesne olamayacağında göre liste boş olmak zorundadır. Bu yüzden de Nil‘in List[Nothing] olarak ifade edilmesi ve List[T] yani T tipindeki herhangi bir boş liste olması mantıklı hale gelmiş olur.
scala> val emptyListOfString:List[String] = List[Nothing]()
emptyListOfString: List[String] = List()
scala> val emptyListOfInt:List[Int] = List[Nothing]()
emptyListOfInt: List[Int] = List()
scala> val nonEmptyIntListCannotBeDefinedThisWay:List[Int] = List[Nothing](1)
:7: error: type mismatch;
 found   : Int(1)
 required: Nothing
       val nonEmptyIntListCannotBeDefinedThisWay:List[Int] = List[Nothing](1)
scala> def f(x:Nothing) = println("foo")
f: (x: Nothing)Unit
scala> f(5)
:9: error: type mismatch;
 found   : Int(5)
 required: Nothing
              f(5)
                ^

Yukarıdaki örnekteki f fonksiyonuna dikkat! Bu metodu hiçbir zaman çağıramazsınız. Zira çağıracak hiçi hiçbir zaman yaratamayacaksınız!
Nothing Scala’da hiç bitmesini istemediğimiz fonksiyonların dönüş tipi olarak kullanılır. Bir fonksiyonun dönüş tipi Nothing ise ve Nothing diye bir nesne üretemeyeceğimize göre bu fonksiyon bu tipte hiçbir değer üretemeyeceği için bitemeyecektir!
Nothing ile ilgili bir başka şey Null tipinin Nothing’den türemesidir. Null scala’da tanımlı bir başka tiptir ve sadece ama sadece bir objesi (instance’ı) vardır o da null’dur. null Java’daki null’un aynısıdır hiçbir nesneye referans olmayan bir değeri ifade etmek için kullanılır.
“Nil, Nothing, Null… Bunlara ne gerek vardı?”, “Java’daki gibi null neyinize yetmedi de bunları uydurdunuz?” diyebilirsiniz. Bunlar programlama mantığı açısından bakıldığında hem olması gereken yapılar hem de programlamada düşülen bazı tuzakları önlemek, programcının işini kolaylaştırmak adına iyi bir programlama dilinde olması gereken özellikler.



Bu Sayfayı Paylaş:

İletişim Bilgileri

Takip Et

Her Hakkı Saklıdır. Bu sitede yayınlanan tüm bilgi ve fikirlerin kullanımından fibiler.com sorumlu değildir. Bu sitede üretilmiş , derlenmiş içerikleri, fibiler.com'u kaynak göstermek koşuluyla kendi sitenizde kullanılabilirsiniz. Ancak telif hakkı olan içeriklerin hakları sahiplerine aittir