Ada Programlama Dili Temelleri

Bölüm 4

Kullanıcı Tanımlı Veri Tipleri

Bölüm 4 Sayfa 2

4.5 - Sayılabilir (Enumeration) Tipinde Veriler

Sayılabilir tipte veriler, aslında tek bir veri tipi değil bir tür veri topluluğudur. Bu veri tipinde, veriler bir isim altında araya virgül konarak yerleştirilir. Genellikle verilerin haftanın günleri, yılın ayları, unvanların hiyerarşik sırası gibi mantıklı bir yerleşim sırası vardır.

Standart pakette, Boolean ve Character adında iki tane sayılabilir (Enumeration) tipi veri, öntanımlı olarak tanıtılmıştır. Bu veri tiplerinin incelemesi sırasında, sayılabilir verilerin tanıtıldığı bilgiler verilmiştir.

Sayılabilir tipte bir verinin tanıtımı için sözdizimi,

enumeration_type_definition ::= 
   (enumeration_literal_specification  {, enumeration_literal_specification})
 
enumeration_literal_specification ::=  defining_identifier  | defining_character_literal
 
defining_character_literal ::= character_literal

şeklindedir. Bu söz dizimi, sayılabilir tipte bir verinin belirli bir tanımlayıcı ile tanıtılacağını, elemanların sayılabilir literaller veya karakter literalleri olabileceğini, araya virgül konularak istenildiği kadar eleman tanıtılabileceğini, elemanların tanımlayıcıların standart tanıtımlayıcı karakteristiklerini taşıması gerektiğini belirtmektedir.

Her sayılabir verinin tanımlanması ve sayılabilir veri içindeki elemanların tanımlayıcıları, birbirlerinden farklı olmalıdır.

Sayılabilir bir veri literalini tanıtan bir tanımlayıcı , tanımlayıcının veya tanımlayıcı karakter literalinin adında ve sonucu sayılabilir veri tipinin ilk alt tipi olan bir tür parametresiz bir fonksiyon gibidir.

Her sayılabilir veri tipi, konum sayıları 0 dan başlayan elemanlar içerebilir. Her sayılabilir veri literali, belirli bir sayılabilir veri tipine ve belirli bir konum sayısına karşı gelir. Her elemanın konum sayısı, kendisinden önce gelen elemanın bir fazlasıdır.

Sayılabilir veri elemanları içinde büyüklük ilişkilerini elemanların sıra numaraları (konum sıraları) belirler. Sıra numarası büyük olan eleman bir öncekinden daha büyük olarak kabul edilir.

Bu tanıma uygun olarak, aşağıdaki sayılabilir veri tipi örnekleri tanıtılabilir:

type Gün is (pazartesİ, salI, çarşamba, perşembe, cuma, cumartesİ, pazar);

type Ay is (ocak, şubat, mart, nİsan, mayIs, hazİran);

type Renkler is (kahverengİ, kIrmIzI, yeşİl, sarI, turuncu, mavİ, portakal, hakİ, beyaz, sİyah);

type Özel is ('y', a4, KIrmIzI Kordela);
  

Bu sayılabilir veri tiplerinin elemanlarının bazıları ilk bakışta garip gelebilir. Fakat, düşününce hiçbir tuhaflık olmadığını bunun sadece bazı karakterlerlemizin Latin-1 sınıfı dışına atılmasının kötü sonuçlarından kaynaklandığı görülecektir. Herşeyden önce Ada derleyicisi tüm değişken adlarını büyük harflare dönüştürerek değerlendirir. Bunu yaparken Latin-1 spesifikasyonu çerçevesinde tanımlanmış karakter için öntanımlı bir küçük harf/ büyük harf dönüştürme sisteminden yararlanır. Kod sayfası, Latin-1 den Latin-5 (CP-1254) e dönüştürüldüğünde, Latin-1 kod sayıları ile tanımlanmış karakterlerden bazıları Türkçe karakterlerle yer değiştirir. Ada derleyicisi Türkçe alfabenin bazı karakterlerini içeren tanımlayıcıları ile tanıtılmış olan sayılabilir veri elemanlarını yanlış büyük harflare çevirerek algılar. Bunun engellenmesi için spesifik bir pragma bildirimi kullanılması gerekir. Ada derleyicisi, i karakterinin büyük harfini I olarak kabul eder. Oysa Türkçe dilbilgisi kurallarına göre, i harfinin büyük harfinin İ olması gerekir. Yine aynı şekilde, Ada derleyicisi ı harfinin büyük harfini de İ olarak kabul eder oysa bu harf de I olmalıdır. Bu nedenle ı ve i harflerini içeren sayılabilir değerlerde sorun yaşanır. Bu sorunun yaşanmaması için, i harfi içeren değerler İ ile ı harfi içeren değerler I ile tanıtılmalıdır. Örnek olarak, mavi yerine mavI olarak, salı yerine salİ olarak tanıtılır . Bu ayrıntıya dikkat edilirse, Türkçe kod sayfası ile derlenen programlarda, derleyicinin sayılabilir veri değerlerini büyük harflere dönüştürerek algılamasında hiçbir sorun yaşanmaz.

Sayılabilir tiplerin tanıtımları sonrasında, derleyici, elemanlara 0 dan başlayan ve her eleman için bir artarak devam eden tanım sıra numarası (İndis) (Index) atar. Bu indis numaralarından elemanlara erişim için yararlanılabilir.

Aynı tanım bölgesinde aynı tanıtıcı hem bir sayılabilir veri tipi elemanı, hem de bir değişken tanımlayıcısı olarak belirtilemez. Derleyici bu durumda çalişkiye düşer ve derleme sürecinde veri tipinin geliştirilmesi (analiz edilip uygunluğunun denetlenmesi) aşamasında programı kabul etmez.

Tanımlandıktan sonra, sayılabilir verilerin elemanları tanımlanmış değişken satatüsünü kazanır, her türlü uygulamada kullanılabilir ve yeni değerler atanabilir. Örnek olarak, Cumartesİ := Şabat; şeklinde bir atama yasaldır.

Sayılabilir verilerin standart giriş/çıkış ortamında giriş/çıkışlarının sağlanması için uygulanabilecek bir yöntem, bu verilerin sözel imajlarının alınarak, sözel verilerin giriş/çıkış işlemlerini sağlayabilen öntanımlı Ada.Text_IO paketinin metotalarının kullanılması ile giriş/çıkış işlemlerinin gerçekleştirilmesidir. Bu yöntemin uygulandığı bir prosedür aşağıda görülmektedir.

with Ada.Text_IO;

procedure b4_5_uyg_1 is

   type Günler is (Pazartesİ, SalI, Çarşamba, Perşembe, Cuma, Cumartesİ, Pazar);

begin

   Ada.Text_IO.Put(Item => "Haftanın ilk günü : " & Günler'Image(Pazartesİ));

end b4_5_uyg_1;

Bu prosedürün sonucu : 

Haftanın ilk günü : PAZARTESİ

olmaktadır.
  

Yukarıdaki prosedürün sonuçlarından, görüntülenen sayılabilir veri elemanın büyük harfle yazıldığı ve Türkçe karakterlerin CP-1254 altında, uygun bir şekilde girildiğinde, sonucun doğru olarak okunabildiği görülmektedir. Prosedür sonunda veriler büyük harflere dönüştürülerek görüntülenecektir. Bu nedenle, veri Pazartesİ olarak verilmiştir. Burada tek sorunlu karakter İ dir. Bu nedenle doğrudan büyük harf karakteri ile tanımlanmıştır. Derleyici bu veriyi Pazartesİ veya paZARTesİ gibi şekillerle algılayacak fakat asla, pazartesi değil pazartesı olarak algılayacaktır. Bu nedenle, Pazartesİ olarak tanımlanmıştır. Program içinde bu veri pazartesı (küçük ı ile) veya PAZARTESİ (büyük i ile) çağrılabilir. Sonuç her iki durumda da, büyük harfle PAZARTESİ olarak görüntülenecektir.

Sayılabilir veri tiplerinin standart ortamda giriş/çıkışlarının sağlanmasının ikinci bir yöntemi, Ada.Text_IO öntanımlı paketinin sayılabilir veriler için generik bir alt paketi olan Enumeration_IO program paketininin, tanımlanmış olan sayılabilir veri tipi için spesifik bir örneğinin oluşturularak, tanımlanmış sayılabilir veri tipi için, standart ortamda giriş/çıkış işlemleri için kullanılmasıdır.

Bu yöntem, ek4-s4 de ayrıntılı olarak açıklanmıştır. Bu yöntemin uygulandığı bir prosedür aşağıda görülmektedir.

with Ada.Text_IO;

procedure b4_5_uyg_2 is

   type Günler is (PazartesI, Salİ, Çarşamba, Perşembe, Cuma, CumartesI, Pazar);

   package Enum_IO is new Ada.Text_IO.Enumeration_IO (enum => Günler);

   Gün : Günler;

   Küçük_Harf : Ada.Text_IO.Type_Set := Ada.Text_IO.Type_Set'First;

   use type Ada.Text_IO.Type_Set;

begin

   Ada.Text_IO.Put(Item => "Haftanın Günlerinden Birini Giriniz (İlk Harf İstenirse Büyük, Diğerlerinin Tümü Küçük Harflerle) : ");

   Enum_IO.Get(Item => Gün);

   Ada.Text_IO.New_Line;

   Ada.Text_IO.Put(Item => "Girilen Gün : ");

   Enum_IO.Put(Item => Gün , set => Küçük_Harf);

end b4_5_uyg_2;

Bu prosedürün sonucu : 

Girilen Gün : pazartesi

olmaktadır.
  

Yukarıdaki prosedürde, GNAT 2012 derleyicisinin sayılabilir verileri (sayılabilir veri tiplerinin elemanlarının değerleri, çoğunlukla sayılabilir veri şeklinde bir kısayol ifadesi olarak belirtilir), tanımlandıkları karakterlerle veya bu karakterlerin CP-1254 altındaki küçük/büyük harf eşdeğerlerine göre tanıyabildiği görülür. Veriler küçük harflerlerle yazdırılacaktır. Bu nedenle kuçük harfi i ile yazılan veriler I (büyük ı ) ile küçük harfi ı ile olan veriler ise İ (büyük i ) ile salİ verisinde olduğu gibi tanıtılmıştır. Bu verilere Salı, salı, sALı, Salİ (Büyük İ) şeklinde veriler girilebilir, sonuç daima salı olacaktır. Diğerleri de aynı Salı örneğinde olduğu gibidir. Bu verilere, tanıtılan değerler veya küçük/büyük harf eşdeğerleri dışında, örnek olarak SALI gibi değer girilirse, derleyici girilen veriyi tanıyamayacağı için, raised ADA.IO_EXCEPTIONS.DATA_ERROR şeklinde bir veri hatası mesajı vererek programı sonlandıracaktır.

Bazı prosedürlerde, bir sayılabilir veri tipinin elemanı olarak tanımlanmış bir değer, başka bir sayılabilir veri tipinin de elamanları arasında bulunabilir. Buna bindirme (overloading) adı verilir. Ada derleyicleri, bu elemnı en son tanımlandığı sayılabilir veri tipi içinde bulunduğunu varsayar ve önceki tanımları gözardı eder. Bu şekilde derleyici çelişkiye düşmekten kurtulur. Örnek olarak,

type Birinci_Bölge is (Adana, Gaziantep, Mersin, Hatay)
type İkinci_Bölge is (Diyarbakır, Mardin, Urfa, Hatay)
  

şeklinde iki sayılabilir veri tipi tanımında, Hatay bindirilmiş bir elemandır. Çünkü önce Birinci_Bölge veri tipinin elemaı olarak tanımlanmış, sonra İkinci_Bölge sayılabilir veri tipi tanımı sırasında, elemanlar araında yine Hatay tanımlarak bu eleman üzerine bindirilmiştir. Hatay elemanını içeren sayılabilir veri tipleri arasında en son tanımlanan İkinci_Bölge adlı veri tipi tanımlanmış olduğundan, derleyici Hatay elemanını İkinci_Bölge adlı sayılabilir veri tipinin elemanı olarak düşünür ve tüm düzenlemelerini buna göre gerçekleştirir. Örnek olarak, Hatay elemanından önce gelen eleman sorgulandığında yanıt Urfa olur.

Bir prosedürde, bu iki veri tipini tanımlayalaım ve Hatay elemanının ait olduğu veri tipini sorgulayalım. Bunun için üyelik testi (membership test) adı verilen bir sorgulamayı gerçekleştireceğiz. Üyelik sorgulanması in işlemcisi ile gerçekleştirilir. Bu sorgulama, aşağıda görülen prosedürde, gerçekleştirilmiştir.

with Ada.Text_IO;

procedure b4_5_uyg_4 is

   type Birinci_Bölge is (Adana, Gazıantep, Mersın, Hatay);
   
   type İkinci_Bölge is (Diyarbakir, Mardın, Urfa, Hatay);
   
   type Yedek is (Adiyaman, Maraş, Denizli);

begin

   Ada.Text_IO.Put_Line(Item => "Hatay Birinci_Bölge Kapsamında mıdır ? Yanıt : " & Boolean'Image(Hatay in Birinci_Bölge));

   Ada.Text_IO.Put(Item => "Hatay İkinci_Bölge Kapsamında mıdır ? Yanıt : " & Boolean'Image(Hatay in İkinci_Bölge));
   
end b4_5_uyg_4;

Bu prosedürün sonucu : 

Hatay Birinci_Bölge Kapsamında mıdır ? Yanıt : TRUE

Hatay İkinci_Bölge Kapsamında mıdır ? Yanıt : TRUE

olmaktadır.
  

Yukarıdaki prosedür sonucundan da görüldüğü gibi, Hatay literali iki farklı sayılabilir veri tipinin de elemanı olarak tanımlanmakta ve derleyici bu literali her iki sayılabilir veri tipin de elemanı olduğunu kabul etmektedir. Bu literal, bindirilmiş bir literaldir.

Ada derleyicisinin bindirilmiş literallerin kulanıldığı prosedür çağrılarında çelişkiye düşeceği yani prosedürü çağıram bindirilmiş literalin her iki veri tipinin birden üyesi olduğu için, prosedürü çağıran veri tipinin hangisi olduğu konusunda çelişkiye düşeceği birçok literatürde belirtilmektedir. Aslında GNAT 2012 sürümü, çok gelişmiş analiz yetenekleri donatılmıştır ve içeriğin incelenmesi ile prosedürü çağıran veri tipini çelişkisiz olarak saptama yeteneğine sahiptir. Bu konuda , aşağıda görülen prosedür, herhangibir çelişkinin yaşanıp yaşanmayacağının belirlenmesi amacını taşımaktadır.

with Ada.Text_IO;

procedure b4_5_uyg_4 is

   type Birinci_Bölge is (Adana, Gazıantep, Mersın, Hatay);
   
   type İkinci_Bölge is (Diyarbakir, Mardın, Urfa, Hatay);
   
   package Birinci_Bölge_Giriş_Çıkış is new Ada.Text_IO.Enumeration_IO (enum => Birinci_Bölge);
   
   function Bir_Önceki ( İl : in Birinci_Bölge) return Birinci_Bölge is
   
   begin
   
      return Birinci_Bölge'Pred(İl);
      
   end Bir_Önceki;
   
   procedure Önceki_İl ( İl : in  Out Birinci_Bölge) is
   

   begin
   
      İl := Birinci_Bölge'Pred(İl);
      
   end Önceki_İl;
   
      
   Bir_Önceki_İl : Birinci_Bölge;
   
   Hedef_İl : Birinci_Bölge;
   
begin

   Bir_Önceki_İl := Bir_Önceki(Hatay);
   
   Ada.Text_IO.Put("Hatay İlinden Önceki Sırada Olan Birinci Bölge İli : ");
   
   Birinci_Bölge_Giriş_Çıkış.Put(Bir_Önceki_İl);
   
   Ada.Text_IO.New_Line;
   
   Hedef_İl := Hatay;
   
   Ada.Text_IO.Put(Birinci_Bölge'Image(Hedef_İl) & " İlinden Önceki Sırada Olan Birinci Bölge İli : ");
   
   Önceki_İl(Hedef_İl);
   
   Birinci_Bölge_Giriş_Çıkış.Put(Hedef_İl);
   
end b4_5_uyg_4;

Bu prosedürün sonucu : 

Hatay İlinden Önceki Sırada Olan Birinci Bölge İli : MERSİN

HATAY İlinden Önceki Sırada Olan Birinci Bölge İli : MERSİN

olmaktadır.
  

Yukarıdaki prosedürün, sonuçları, aynen beklendiği gibi olmaktadır. Yani, GNAT 2012 derleyicisi, foksiyon ve prosedürü çağıran argüman Birinci_Bölge veri tipinde olduğundan ve Hatay da bir Birinci_Bölge veri tipi elemanı olduğundan, prosedürü çağıran veri tipinin saptanması konusunda bir çelişkiye düşmememiş, doğru veri tipini içeriği analiz ederek doğru bir şekilde saptamıştır. Yani bu konuda eski literatürün verdiği bilgiler belki eski sürüm derleyicilerin davranışı üzerine verilmiş ve artık geçersiz olmuş bilgiler olabilir. Yine de eğer belki prosedürü çağıran veri tipi üzerinde derleyici çelişkiye düşebilir şeklinde bir düşünce olursa, çağıran sayılabilir veri tipinin nitelendirilmesi, (kalifikasyonu) derleyiciye prosedürü çağıran sayılabilir veri tipini açıkça belirtebilir ve çelişki olasılığı tam olarak ortadan kalkar.

Tam nitelendirilmiş (Fully Qualified) sayılabilir bir veri tipinin elemanı

Sayılabilir_Veri_Tipi'(literal)
  

şeklinde belirtilir. Yukarıdaki prosedürde, nitelendirilmemiş sayılabilir veri tipleri ile yürütülmüş olan programın, tam nitelendirilmiş sayılabilir veri tipleri ile yürütüldüğü sürümü, aşağıda prosedürde,görülmektedir:

with Ada.Text_IO;

procedure b4_5_uyg_5 is

   type Birinci_Bölge is (Adana, Gazıantep, Mersın, Hatay);
   
   type İkinci_Bölge is (Diyarbakir, Mardın, Urfa, Hatay);
   
   package Birinci_Bölge_Giriş_Çıkış is new Ada.Text_IO.Enumeration_IO (enum => Birinci_Bölge);
   
   function Bir_Önceki ( İl : in Birinci_Bölge) return Birinci_Bölge is
   
   begin
   
      return Birinci_Bölge'Pred(İl);
      
   end Bir_Önceki;
   
   procedure Önceki_İl ( İl : in  Out Birinci_Bölge) is
   

   begin
   
      İl := Birinci_Bölge'Pred(İl);
      
   end Önceki_İl;
   
      
   Bir_Önceki_İl : Birinci_Bölge;
   
   Hedef_İl : Birinci_Bölge;
   
begin

   Bir_Önceki_İl := Bir_Önceki(Birinci_Bölge'(Hatay));
   
   Ada.Text_IO.Put("Hatay İlinden Önceki Sırada Olan Birinci Bölge İli : ");
   
   Birinci_Bölge_Giriş_Çıkış.Put(Bir_Önceki_İl);
   
   Ada.Text_IO.New_Line;
   
   Hedef_İl := Birinci_Bölge'(Hatay);
   
   Ada.Text_IO.Put(Birinci_Bölge'Image(Hedef_İl) & " İlinden Önceki Sırada Olan Birinci Bölge İli : ");
   
   Önceki_İl(Hedef_İl);
   
   Birinci_Bölge_Giriş_Çıkış.Put(Hedef_İl);
   
end b4_5_uyg_5;

Bu prosedürün sonucu : 

Hatay İlinden Önceki Sırada Olan Birinci Bölge İli : MERSİN

HATAY İlinden Önceki Sırada Olan Birinci Bölge İli : MERSİN

olmaktadır.
  

Yukarıdaki prosedürde, Tam nitelikli sayılabilir veri tiplerinin kullanımı ile derleyicinin çelişkiye düşme olasılığı tamamen ortadan kaldırılmıştır. GNAT 2012 derleyicisi çelişkili olabilecek durumlarla kendisi başa çıkabildiği için, hiçbir zaman tam nitelikli sayılabilir veri tipi tanımlarının yapılması gerekmemektedir. Yine de paranoya stilini benimseyen programcılar için tam nitelikli tanımların yapılmasını engelleyecek bir durum bulunmamaktadır.

Ada programlama dili, sayılabilir veri tiplerinin elemanları olarak karakter literallerini kabul eden az sayıda program dillerinden biridir. Standard pakette tanımlı Character veri tipi bu şekilde tanıtılmıştır. Örnek olarak,

type Türkçe_Farklı_Karakterler procedure  is ('ı' , 'İ' , 'ş', 'Ş', 'Ğ', 'ğ');
  

elemanları karakter literalleri olan bir sayılabilir veri tipidir. Bu veri tipinin Character ve Wide_Character veri tipleri ile bir ilgisi yoktur. Türkçe_Farklı_Karakterler veri tipi, Character veri tipinden farklıdır ve elemanlarının Ada.Text_IO öntanımlı paketinin metotlarından yararlanılarak standart ortamda giriş/çıkışları sağlanamaz. Bunun için diğer sayılabilir veriler için uygulanan yöntemlerden yararlanılması gerekir.

Sayılabilir verilerin elemanlarının gerçekte kuramsal olarak birer fonksiyon oldukları belirtilmişti. Kuramsal da olsalar her fonksiyon gibi bu tür fonksiyonların da yeniden adlandırılması olanağı bulunmaktadır. Örnek olarak bir X_Pack paketinde tanımlanmış Renk sayılabilir veri tipinin Yeşil isimli elemanı, eğer X_Paketi görünür durumda ise,

function Yeşil return X_Paketi.Renk renames X_Paketi.Yeşil;
  

şeklinde yeniden adlandırılabilir ve bu şekilde use X_Pack bildirimine gerek olmadan X_Paketinde tanımlı Renk sayılabilir veri tipinin Yeşil elemanına erişilebilir. Doğal olarak, bu sıradışı yönteme nadiren başvurulur.

Sayılabilir verilerin alt tipleri tanımlanabilir. Örnek olarak,

subtype Bir_Kısım_Türkçe_Farklı_Karakterler is Türkçe_Farklı_Karakterler range 'ı' .. 'ş';
  

Bir sayılabilir veri tipi, alt tipi tanımıdır.

4.5.1 - Enumeration Veri Tipine Uygulanabilen Nitelikler

Sayılabilir veri tipi skaler, ayrık bir veri tipidir ve bu tip verilere uygulanabilien tüm nitelikler bu veri tipi için de uygulanabilir . Bu konuda bir sayılabilir veri alt tipi olan Boolean veri tipinde bu konuda geniş uygulama örnekleri verilmiştir.

4.5.2 - Enumeration Veri Tipi İçin Tanımlı İşlemciler

Sayılabilir veri tipindekli nesneler için aritmetik işlemciler tanımlanmamıştır. Sadece ilişkisel işlemciler olan "=' , "<" , "<=" , "=" , "/=" , " >= ", ">" işlemcileri ve üyelik işlemcisi olan in işlemcisi tanımlıdır. Bu işlemcilerin uygulamaları bir sayılabilir veri alt tipi olan Boolean veri tipi incelenirken yapılmıştır.