İçeriğe geç →

Closures (Ruby)

Geçtiğimiz günlerde daha iyi bir yazılım geliştiricisi olmak üzere sık kullandığım dillerde neleri az kullanıyorum ve geliştirebilirim diye araştırdığımda, karşımda ağırlıklı olarak Closure, Fonksiyonel Programlama, Metaprogramming gibi kavramları buldum.

Aslında bu gibi kavramlardan uzun süredir haberim var ve pratikte kullanıyorum. Fakat daha derine gitmek istediğim şey neden ihtiyaç oldukları ve bunları kullanmanın yazılım geliştirmeye yeni başlayanlara nasıl mantıklı bir şekilde izah edebileceğimi bulmaktı. Bu konu hakkında hazırlayacağım bir yazı dizisinin ilk ayağını Ruby dilinde Closure‘lar oluşturacak.

2007 yılından itibaren Ruby programlama dili ile yazılım şirketleri, reklam ajansları, girişimler için uygulamalar geliştiriyorum. Portfolyo

Şunu belirtmeliyim ki Closure kelimesinin Türkçe karşılığını araştıracak, ihtiyaç duyacak arkadaşlar Tureng, Wikipedia gibi kaynakları inceleyebilirler. Ben yazıya dil kaygısı taşımadan Closure şeklinde devam edeceğim.

Closure Nedir?

Bu kavram, genellikle kullandığımız kod parçalarından farklı bir tanımlama içermiyor, yine döngüler, karar mekanizmaları, tanımlamalar kullanıyoruz. Fakat bunları kullanma şeklimizle ilgili yaptığımız farklılıklar, kod parçalarının çalışma, okunma, tekrar kullanım gibi özelliklerine pozitif katkılarda bulunuyor. Bu pozitif katkılar, üretim kabiliyetimizi ve hızımızı arttırırken, günümüzün ihtiyaç duyduğu ürünlere üretim karşılığı verebilmemizi sağlıyor. Tanımından kabaca bahsedelim ve daha çok örneklerle açıklamaya çalışalım.

Closure, içerisinde işlem yapılan değerlerin, bir üst bloğun içerisinde tanımlandığı kod bloğudur. Atama işlemleri genellikle blok içerisinde yapılmaz ve kod bloğu içerisine gönderilen değer üzerinde bir hesaplama ile sonuç üretir. Daha iyi anlamak için iki programlama konseptine hakim olmak gerekiyor.

Lexical Scoping

Değişkenin son atamasının yapıldığı en yakın yerin bulunduğu kod bloğudur. Değişken değerinin hangi satırda, scope içerisinde hangi değere sahip olduğunu gözlemleyerek, bu scope’u bulabiliriz. Örneğin;

Yukarıdaki Ruby kod örneğinde, msg isimli değişkenin içerisine bir yazı atıyorum. Ardından 3 defa dönen bir döngü içerisinde prefix değişkeni içerisine başka bir yazı atıyorum. En sonunda puts ile başlayan satırda bu iki yazıyı birleştirerek ekrana yazıyorum. do .. end arasındaki kod bloğu bir scope oluşturuyor. msg değişkeninin olduğu bölüm ise do .. end scope’unun üst scope’u. msg değişkeni tanımlandığı scope içerisinde, yani alt scope’u olan do .. end bloğu arasında kullanılabiliyor. prefix değişkeni ise do .. end scope’u içinde tanımlandığı için üst scope’u tarafından bilinemez halde.

Free Variable

Üst scope içerisinde tanımlanmış bir değerin, bir kod bloğu içerisine parametre olarak yollandığı durumlarda bu değere free variable deniyor. Lexical Scope konusunda bahsettiğimiz örnekte free variable kullanarak değişiklik yapalım:

Yukarıdaki örnek, Lexical Scope konusundaki örneğin aynısı fakat tek bir farkla, do .. end bloğu ile bir scope oluşturulmak yerine, Lambda ile bir scope oluşturuluyor. Lambda Ruby dilinde anonim fonksiyonlar oluşturulmak için kullanılıyor. Yani ismi olmayan ve bir değişkene atanabilen bir scope tanımlanıyor. Eğer bu bloğa bir isim isim verecek olsaydık bu sefer method (fonksiyon) oluşturmuş olacaktık.

İlk satırdaki iki çizgi (pipe) arasındaki msg değer, scope’a bir değer gönderebilmemizi sağlıyor. Bu örnekte msg, bu scope için tanımlanan free variable oluyor. chalkboard_gag değişkenine atadığımız bu anonim fonksiyonu call methodu ile şu şekilde çağırıyoruz:

Farkettiyseniz, iki lambda iç içe geçmiş şekilde. chalkboard_gag değişkeni üzerinde call metodunu “drive the principal’s car” değerini göndererek çağırıyoruz. Free variable olan msg değeri “drive the principal’s car” oluyor. Ve artık lambda ile tanımlanan scope içerisinde msg değişkeninin geçtiği her yerde bu değere sahip olacak (bir daha değiştirilene kadar). Artık inner_lambda değişkeni içerisinde içteki ikinci lambda ile tanımlanan scope bulunuyor. Bu anonim fonksiyonu da çağırarak, iki metnin birleştirilmesi işlemini tamamlayacağız:

Şu anda result değişkeninin değeri, inner_lambda değişkeninin üzerinde de call metodu kullanarak, “#{prefix} #{msg}” nin karşılığı olan “I will not drive the principal’s car” değeri tanımlı.

Closure tanımlayabilmek için bir fonksiyon oluşturmalı (anonim) ve parent scope‘ta tanımlanmış bir değişkene referans gösterilmeli. Proc ve Lambda kullanmak tek başına yeterli değil, parent scope‘ta tanımlanmış en az bir değişken tanımlaması da olmalı. Buna da free variable deniyor.

Bir Ruby Class’ını Closure ile Simülasyonu

Aşağıda Object Oriented Programming geleneklerine uygun şekilde oluşturulmuş bir Ruby Class’ı var:

Şimdi bu sınıfı Closure tanımlamalarıyla nasıl oluştururduk görelim:

Lambda Nedir?

Ruby programlama dilinde kod blokları (scope) oluşturmaya ve tekrar kullanımlarını sağlamaya yarar. Anonim metodlar oluşturularak kod bloklarının tekrarlı kullanımlarını kolaylaştırır.

Değişkenlere atanabilir

Metodlara (Fonksiyonlara) değer olarak gönderilebilir

Metodların (Fonksiyonların) dönüş değeri olabilir


Burada bahsedilen konu ve örnekler için Mastering Ruby Closures kitabından yararlandım. İngilizce olan bu kitapta bu konu ile ilgili daha detaylı bilgiler bulabilirsiniz.

Kategori: Yazılım

Yorumlar

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir