2 Temmuz 2014 Çarşamba

Ruby'de Soyut veri Tipleri ve Nesneye Yönelik Programlama Kavramları

  1. Ruby'de Soyut Veri Tipleri

Ruby soyut veri tipleri için desteği “sınıf” yapısı ile verir. Ruby sınıfları kabiliyetleri bakımından C++ ve Java sınıfları ile benzerlik gösterir [6]. İleriki bölümlerde soyut veri tiplerinin özellikleri, nesneye yönelik programlama ile birlikte verilecektir.

  1. Ruby'de Nesneye Yönelik Programlama

Ruby nesneye yönelik bir programlama dili olarak tasarlanmıştır ve saf bir nesneye yönelik programlama dili olarak görülür. Ruby'de her şey bir nesne olarak görünür. Ruby'deki karakter katarı, sayı ve mantıksal ifadeler gibi en basit veri tiplerinin değerleri bilenesne olarak tutulur [1,2,3].

puts 1.class => "Fixnum"
puts true.class => "TrueClass"
puts nil.class => "NilClass"

  1. Sınıf Tanımı

Ruby’de sınıflar “class” anahtar kelimesi ve sonrasında gelen büyük harf ile başlayan bir isimle tanımlanır ve Ruby'deki bir çok yapı gibi “end” ifadesi ile tanım sonlandırılır [2]. Aşağıda basit bir sınıf tanımı görülmektedir:

class RubyClass
end

    • Sınıf İlklendirmesi / Nesne Oluşturulması

Ruby’de tanımlanan bir sınıftan “new” sayesinde nesne oluşturulabilir [4].

ruby1 = RubyClass.new
ruby1.is_a? RubyClass # => true

Bir sınıf ilk defa ilklendirildiğinde initialize yapılandırıcı metodu çağrılır [4].

class RubyClass2
 def initialize(value1, value2, value3)
   @v1 = value1
   @v2 = value2
   @v3 = value3
 end
end

Sınıftan nesne oluşturulurken “new”e geçirilen her parametre initialize metoduna aktarılır ve ilklendirmede kullanılır. Metod aşırı yükleme (overloading) RubY'de bulunmadığından bir sınıfın sadece bir yapılandırıcı initialize metodu vardır.

ruby2 = RubyClass2.new(1,2,3)

    • Değişken Tipleri ve Erişim Yöntemleri

Örnek (instance) değişkenler @ ile başlarlar ve nesneye aittirler. Etki alanı self nesnesi ile yani oluşturulan nesne ile sınırlıdır. Değerleri diğer nesnelerle paylaşılmaz. Nesne dışından erişilemez. Erişim için değişkene özgü metod tanımlanmalıdır [4]. Ruby'de değişkenlerin tanımlanmasına gerek yoktur.

class RubyClass3
 def initialize(value1)
   @v1 = value1
 end

 # Erişim metodu (getter)
 def v1
   @v1
 end

 # Değer verme metodu (setter)
 def v1(value1)
   @v1 = value1
 end

 # Sınıf içinden sınıf değişkene self ile erişilebilir
 def v1reset
   self.v1 = 0;
 end

end

ruby3 = RubyClass3.new(1)
puts ruby3.v1 # => 3

Örnek değişkenlere erişim metodları otomatik oluşturulabilir. “att_reader” anahtar kelimesi sayesinde sadece erişim metodu tanımlanırken, “att_accessor” anahtar kelimesi sayesinde sadece erişim metodu tanımlanır [4].

class RubyClass4
 attr_accessor :v1;
end

Sınıf değişkenleri yani tüm nesneler tarafından paylaşılan değişkenler ise @@ ile başlarlar. Bir sınıfı miras alan alt sınıflar tarafından da erişilebilirler [5].

Sınıf sabitleri ise büyük harfle başlarlar ve yanlızca bir defa değer atamasına izin vardır.ğer yeniden değer ataması yapılırsa, hata değil uyarı mesajı verilir. Sabitler sınıfla beraber tanımlanmalıdır ancak, örnek değişkenlerin aksine sınıf ismiyle beraber belirtilerek (Ör. sinif::SABIT şeklinde) sınıfın dışından da erişilebilirler [5].

Yerel değişkenler ise küçük harfle ya da “_” karakteriyle başlar. Yerel değişkenler genel ya da örnek değişkenlerde olduğu gibi, başlangıçta nil değerine sahip değildirler, çünkü atama yapmadan gerçekte oluşmazlar. Yerel bir değişkene yaptığınız ilk atama onu bildirmekle aynı şeydir. Eğer başlangıç değeri olmayan bir yerel değişkene başvurursanız, Ruby yorumlayıcısı bunun bir yöntemi çalıştırma girişimi olduğunu düşünür ve hata verir [5].

    • Erişim Kontrolü / Bilgi Saklama (Information Hiding)

Ruby'de public, private ve protected olmak üzere 3 tip erişim kontrolü tanımlanmıştır. Bunlar önüne geldikleri değişkenin erişim özelliğini değiştirirler. Ruby'de ön tanımlı oalrak metodlar “public”, değişkenler ise “private” dır [2].
  • Public : Erişim her yerden sağlanabileceğini belirtir.
  • Private: Erişimin nesne içinde kısıtlandığını belirtir.
  • Protected: Erişimi alt sınıflardan da mümkün kılar.
  1. Miras

Ruby'de alt sınıf tanımı yapılırken üst sınıftan miras “<” sembolü sayesinde gerçekleştirilir. Üst sınıftaki metodlar ve değişkenler alt sınıf tarafından miras alınırlar [7].

class RubyClass5A
 def initialize(value1)
   @v1 = value1
 end
end

class RubyClass5B < RubyClass5A
 def initialize(value2)
   @v2 = @v1 + value2
 end
end

Ruby'de çoklu miras desteklenmez [5].

    • Method Ezme (Overriding)

Ruby'de üst sınıfta tanımlanmış bir metod aynı şekilde alt sınıfta tanımlanırsa, alt sınıf için üst sınıftaki metodun tanımı geçersiz yapılıp yenisi tanımlanmış olur [2].

class RubyClass6A
 def metodX
   puts “6A”
 end
end

class RubyClass6B < RubyClass6A
 def metodX
   puts “6B”
 end
end

    • Operatör Yeniden Tanımlama (Overloading)

Ruby'de hem standart tipler için hem de programcı tanımlı sınıflar için  operator yeniden tanımlanması (overloading) mümkündür [2].

class Kutu
 def initialize(en,boy)
   @en,@boy = en, boy
 end

 def +(diger)
   Kutu.new(@en + diger.en, @boy + diger.boy)
 end

 def -@
   Box.new(-@en, -@boy)
 end

 def *(sayi)
   Box.new(@en*sayi, @boy*sayi)
 end
end

  1. Ara Yüz (Interface)

Ruby soyut sınıfları veya ara yüz (interface) tanımlamayı desteklemez [6]. Bununla beraber, her ne kadar gerçek bir ara yüz tanımının yerini tutmasa da, Ruby'deki mevcut sınıfları kullanılarak interface benzeri yapılar oluşturmak mümkündür [7,8].

class Dil
 def merhaba
   raise NotImplementedError
 end
end

class Turkce < Dil
 def merhaba
   puts "Merhaba"
 end
end

  1. İsimlendirme Sarmalaması (Naming-Encapsulation) Yapıları

Ruby'de modül (module) yapılarının örneği ve alt sınıfı tanımlanamaz. Ruby modülleri  bir isimlendirme sarmalı oluşturmak için sıklıkla kullanılır ve fonksiyonların bir kütüphanesini oluşturmak için faydalıdır. Bir modülün kullanılabilmesi için modül “requşre” anahtar kelimesi ile belirtilir. Modüllerin fonksiyonlarına direk erişim mümkündür. Bu nedenle bir nevi çoklu miras bu şekilde sağlanır [6].
  1. Dinamik Bağlama

Ruby dinamik tip tanımlı bir dildir. Değişkenler bir tipe sahip değildir, aslında değişkenler her hangi bir sınıfın nesnesine referans verirler. Bir değişken her hangi bir sınıfa referans verebildiği için aslında çok yüzlülük (polymorphism) sağlanmış olur [6].


[1] "Ruby Programming Language”, http://en.wikipedia.org/wiki/Ruby_(programming_language), Erişim: 27 Mayıs 2014.

[2] “Object Oriented Ruby”, http://www.tutorialspoint.com/ruby/ruby_object_oriented.htm, Erişim: 27 Mayıs 2014.

[3] “Ruby Programming/Data Types”, Wikibooks, http://en.wikibooks.org/wiki/Ruby_Programming/Data_types. Erişim Tarihi: 24 Nisan 2014.

[4] Flanagan D., Matsumoto Y., The Ruby Programming Language, O'Reilly Media, 2008.

[5] M. Slagell and P. Yanardağ, "Ruby Kullanıcı Kılavuzu," 22 Nisan 2003. [Çevrimiçi]. Available: http://pdf.belgeler.org/uygulamalar/ruby/ruby-ug.pdf, Erişim Tarihi: 27 Mayıs 2014.

[6] Sebesta, R.W., Concepts of Programming Languages, Pearson Education, 2012.

[7] “Ruby Interfaces”, http://briancarper.net/blog/226/. Erişim Tarihi: 27 Mayıs 2014.

[8] “What is java interface equivalent in Ruby?”,  http://stackoverflow.com/questions/4437291/what-is-java-interface-equivalent-in-ruby. Erişim Tarihi: 27 Mayıs 2014.

NOT: YTÜ - İleri Programlama Dili Dersi 2014 1. Dönem Ödevi Çerçevesinde Hazırlanmıştır.

NOT 2: Ruby 1.9 baz alınmıştır.

1 Temmuz 2014 Salı

Ruby'de Alt Yordamlar

  1. Alt Yordamlar

Altyordam, belirli bir iş yapan bir dizi program ifadesinin bir birim altında toplanmasıdır. Altyordamlar, farklı programlama dillerinde prosedür, fonksiyon, metot, alt program vb. farklı isimler almaktadır [1].


Altyordam kavramı, Ruby gibi nesneye yönelik programlama dillerindeki metot kavramıyla benzerlik gösterir. Metotlar, çağrım yöntemleri ve sınıflarla ilişkileri bakımından alt yordamlardan farklılık gösterirler [2].


  1. Metotlar

Ruby’de iki parametre alan basit bir metot tanımı ve metodun parametre ile çağrımı gösterilmiştir:


def azalt(deger1, deger2)
 deger1 -= 1
 deger2 -= 1
end

a = 1;
b = 10;
azalt(a, b);
puts a; # Değer değişmez, a=1
puts b; # Değer değişmez, b=10


    • Metot Dönüş Değeri

Ruby’de metotlar return ifadesi ile döndürdükleri değeri belirtmek zorunda değillerdir. Ruby’de metot dönüş değeri metotta işletilen son ifadenin sonucudur [3].


Ruby’de metotlar birden fazla değer dönebilirler [3].


Ruby’de metotlar def ifadesi ile tanımlanır undef ifadesi ile de tanımsız hale getirilebilirler [3].


  1. Metot Argümanları/Parametreleri

Ruby’de basit bir metot tanımı virgüllerle ayrılmış şekilde sayısız parametre alabilir [3].


    • Ön Tanımlı (Default) Parametre Değeri Belirtme

Ruby'de metotta tanımlı parametrelere ön tanımlı (default) bir değer belirtebiliriz. Bu ön tanımlı değerler, metot çağrıldığında işletildiği için dinamik değer de alabilirler [3].


def ilkharfler(s, uzunluk=1)
s[0, uzunluk]
end

ilkharfler("Ruby", 3) # => "Rub"

ilkharfler ("Ruby") # => "R"


    • Opsiyonel Parametreler

Bazen metotlara opsiyonel ve keyfi sayıda parametre verme ihtiyacı olabilir. Ruby’de bunu yapabilmek için bir parametrenin önüne * koymak yeterlidir. Böylece bu opsiyonel parametre sıfır veya daha fazla değere sahip bir dizinin referansı haline gelir [3].


# Maksium değeri bul
def maksimum(ilk, *digerleri)
# İlk verilen değerin en büyük olduğunu kabul et
maks = ilk
# opsiyonel paramterlere daha büyüğünü bulmak için tek tek bak
digerleri.each {|x| maks = x if x > maks }
# En buyuk değeri dön.
maks
end


Yukarıda tanımlı maksimum fonksiyonuna bir dizi parametre olarak verilmek istenirse ve dizinin değerlerinin fonksiyondaki parametrelere sırasıyla dağıtılması istenirse yine * operatörü kullanılabilir [3]. Örneğin:


dizi = [3, 2, 1]
m = maksimum (*dizi) # ilk = 3, digerleri =[2,1] => m=3


    • Blok Fonksiyon Parametresi

Ruby’de fonksiyonlar direkt olarak parametre geçilemese de , blok fonksiyon isimli özel bir çağrım yöntemi ile bir nevi fonksiyon çağrımı yapılabilir [3]. Örneğin:


def seri(n, m, c, &b) # &b: blok fonksiyon
i = 0
while(i < n)
   b.call(i*m + c) # Blok fonksiyonu çağır
   i += 1
end
end

seri(5, 2, 2) {|x| puts x }


    • Parametre Geçirme Yöntemi

Ruby'de fonksiyona verilen parametrenin değeri geçirilir (pass by value) [4]. Genelde karıştırılsa da parametrenin sadece değerinin geçirilmesi nesneler için de geçerlidir. Şöyle ki, nesneler ise aslında gerçek bir değer tutmayıp, hafızada bir referansı tutarlar, fonksiyona parametre olarak da bu referansın değeri geçirilir. Bu sayede nesne üzerinde değişiklik yapılabilir ancak nesne başka bir nesneye atanamaz. Bu açıdan Ruby Java’ya benzer [4,5].


    • Parametre Tipleri ve Tip Kontrolü

Ruby dinamik tipli (dynamically typed) bir dil olduğu için metotlarda parametre tipi belirtilmez. Paramtre tipindeki bir uygunsuz durum ancak parametre işletildiğinde hata verir[6].


    • Fonksiyon Aşırı Yüklemesi (Overloading)

Ruby’de aynı isimli iki fonksiyon tanımlanamaz [7].



[1] "Subroutine”, http://en.wikipedia.org/wiki/Subprogram. [Erişim Tarihi: 23 Mayıs 2014].


[2] Sebesta, R.W., Concepts of Programming Languages, Pearson Education, 2012.


[3] Flanagan D., Matsumoto Y., The Ruby Programming Language, O'Reilly Media, 2008.


[4] “Ruby - Parameters by reference or by value”, 3 Nisan 2014,  http://stackoverflow.com/a/22827949/878710. [Erişim Tarihi: 23 Mayıs 2014].


[5] “Is Java “pass-by-reference” or “pass-by-value”?”, 12 Ağustos 2011,  http://stackoverflow.com/a/7034719/878710. [Erişim Tarihi: 23 Mayıs 2014].


[6] “Ruby Programming/Syntax/Literals”, Wikibooks, http://en.wikibooks.org/wiki/Ruby_Programming/Literals . [Erişim Tarihi: 23 Mayıs 2014].


[7] “Ruby Overloading Methods”, http://rubylearning.com/satishtalim/ruby_overloading_methods.html. [Erişim Tarihi: 23 Mayıs 2014].


NOT: YTÜ - İleri Programlama Dili Dersi 2014 1. Dönem Ödevi Çerçevesinde Hazırlanmıştır.

NOT 2: Ruby 1.9 baz alınmıştır.