Ada Programlama Dili — Paketler (Packages)
Bugünkü makalemizde modüler yapı başlığı altında bulunan paketlere değineceğiz. Fakat paket konusu Ada programlama dilinde büyük bir yer kapladığı için, bu yazımızda paket kullanımının yalnızca bir kısmına değindik ve şu soruları cevaplamaya çalıştık: Bir paket nasıl oluşturulur? Paketlerin kullanımı nasıldır? Hiyerarşik bir paket sistemi nasıl yapılır? Alt paketlerin kullanımı nasıl gerçekleştirilir? Özel paketler nedir? vb. Ayrıca makalenin daha iyi anlaşılabilmesi için örnek olarak tek bir paketi ele aldık ve bu paketin nasıl genişletilebildini anlatmaya çalıştık.
Her ne kadar metot ve fonksiyon kullanarak program kodlarını modüler bir hale getirebilsek de, paketler ise bize bir üst yapı kurma olanağı sağlar. Daha açık bir ifadeyle söylemek gerekirse; paketler, türlerin, alt türlerin, sabitlerin ve alt programların anlamlı bir şekilde gruplandırılmasına imkân tanırlar. Bunun yanında bir paket daha küçük birimlere, yani alt paketlere de bölünebilir. Bu sayede daha organize edilmiş bir kod elde ederiz.
Bir paket, başlık (package header veya specification) ve gövde (package body) olmak üzere iki bölümden oluşur. Başlık kısmında, paket içerisinde kullanılacak olan türler, alt türler, değişkenler, metotlar, fonksiyonlar vb. bulunabilir. Gövde kısmında ise paketin sahip olduğu uygulama vardır. Ayrıca her gövde için bir başlık kısmı bulunmalıdır, ancak bunun tersi mecbur değildir. Örneğin; yalnızca türleri, sabitleri ve değişkenleri içeren bir paket için genellikle gövdeye gerek olmaz.
Sözdizimi
Yukarıda da bahsedildiği gibi bir paket, başlık ve gövde olmak üzere iki kısımdan oluşur. Başlık kısmı .ads
uzantılı bir dosya içerisinde bulunurken, gövde kısmı ise .adb
uzantılı bir dosyaya yazılır. Hal böyle olunca karşımıza birbirine çok benzeyen iki farklı sözdizimi çıkmaktadır.
Bir paketin başlık kısmına ait sözdizimi şu şekildedir:
-- <Package_Name>.ads
package <Package_Name> is
-- Başlık bölümü:
-- paket içerisinde kullanılacak değişkenler, sabitler, tür tanımları,
-- alt programlar vb. öğeler tanımlanır
-- NOT: Dışarıdan erişimin sağlandığı alan (public)
private
-- NOT: Dışarıdan erişimin kısıtlandığı alan (private)
end <Package_Name>;
Bu sözdiziminden anlaşılacağı üzere, bir paket başlığı içerisinde herkesin ulaşabileceği bir yer (public) olsa da kısıtlı bir alan (private) da mevcut. Kısıtlı alanda bulunanlara yalnızca o paket içerisinden erişim sağlanabilir ve böylece bulunduğu paketin gövdesinde kullanılabilirler. Böylece diyebiliriz ki paketler, veri gizlemenin, yani kapsüllemenin (encapsulation) yönetildiği yerlerdir.
Bir paketin gövde kısmına ait sözdizimi de aşağıdaki gibidir:
-- <Package_Name>.adb
package body <Package_Name> is
-- Gövde bölümü:
-- alt programlar icra edilir
end <Package_Name>;
Paketlerin gövde kısmında genellikle alt programlar bulunur. Tabii ki her bir alt program kendi içerisinde pek çok tür, alt tür, metot, fonksiyon vb. barındırabilir. Fakat bunlar yalnızca tanımlı oldukları alt programın kapsamında kalırlar.
Oluşturulan bir paketi diğer birimler içerisinde kullanabilmek için with
anahtar kelimesine ihtiyaç vardır. Paketin bir öğesine de nokta (.
) ayracı yardımıyla erişebiliriz. Noktanın solunda paketin adı, sağında ise erişilmek istenen öğe bulunur: <Paket_Adı>.<Paketin_Öğesi>
. Yani bir paket, bir alan adını (namespace) da beraberinde getirir. Şayet paketin öğesine erişmek için her defasında nokta kullanımından kurtulmak istenirse, use
anahtar kelimesinden yararlanılır: use <Paket_Adı>
. Buna ek olarak hemen şunu da belirtelim; use
anahtar kelimesinin etki alanı bulunduğu yere göre değişiklik gösterir. Daha açık bir şekilde ifade edecek olursak; eğer bir dosyanın başında use
kullanılırsa, o paketin öğelerine erişmek için dosyanın tamamında nokta kullanımına gerek kalmaz. Şayet use
anahtar kelimesi bir alt programın veya kod öbeğinin öğeler kısmındanda bulunursa, etki alanı yalnızca bulunduğu blok ile sınırlıdır. Bu çeşit farklı kullanımlar aşağıdaki örneklerde sunulmuştur. Dikkat edilmesini rica ederim.
Son olarak şunu da hatırlatmakta fayda var: GNAT derleyicisi kullananların dikkat etmesi gereken husus da bir paketin adı ile bulunduğu dosyanın adının aynı olması gerekmektedir. Aksi halde kodunuz her ne kadar sorunsuz derlense de derleme aşamasında devamlı bir uyarı ile karşılaşırsınız.
Kullanım Yöntemleri
Ada dilinde paket kullanımı çok yaygındır. Hatta diğer dillerde bulunan bir çok teknik paketler sayesinde gerçekleştirilir. Yani paketler, yazılımcının gereksinimine göre farklı şekillerde kullanılmaya olanak sağlarlar. Şimdi sırasıyla bu yöntemlerin bir kısmına değinelim.
Bir paket, programın her yerinden erişilebileceği en genel türleri, alt türleri, değişkenleri, sabitleri ve alt programları (metotlar ve fonksiyonlar) içerisinde barındırabilir. Ayrıca bu paketin gövde kısmı da olmayabilir. Yani tüm öğeler yalnızca .ads
dosyası içerisinde bulunur. Buna ek olarak, bu tür kullanıma sahip paketlerde genellikle private
kısmı da bulunmaz.
-- math.ads
package Math is
type Byte is mod 256;
PI : constant Float := 3.141_59;
E : constant Float := 2.718_28;
Catalan : constant Float := 0.915_96;
function Add (X, Y : Integer) return Integer is (X + Y);
function Sub (X, Y : Integer) return Integer is (X - Y);
function Mul (X, Y : Integer) return Integer is (X * Y);
function Div (X, Y : Integer) return Integer is (X / Y);
end Math;
Yukarıdaki örnekte de görüleceği üzere, Math
adında bir paket oluşturulmuş; ve bu paketin içerisinde programın her yerinden erişime açık, en genel tanımlar ve alt programlar bulunuyor. Fakat burada dikkat edilmesi gereken husus da şudur; bu şekilde genel kullanıma sahip bir paket içerisinde değişken tanımlamak pek iyi bir fikir değildir. Çünkü global tanımlanmış bir değişken, program çalıştığı sürece pek çok yan etkiye neden olabilir.
Bir paket, başlık kısmında bulunan alt programların içeriğini gövde kısmına alınması suretiyle kütüphane gibi de kullanılabilir. Bu yöntem her ne kadar işletim sistemi seviyesinde bir kütüphane oluşturmaya olanak sağlasa da; burada bahsedilen olay, böyle bir paketin, bulunduğu uygulama içinde bir kütüphane gibi kullanımından öteye gitmiyor.
Eğer bir paketin başlık kısmında türlerin, alt türlerin, değişkenlerin, sabitlerin ve alt programların yalnızca tanımları bulunuyorsa, bu paketin bir de gövde kısmına ihtiyacı vardır. Örneğin, yukardaki kodda bulunan Add
, Sub
, Mul
ve Div
fonksiyonlarını başlık kısmında tanımlayabilir, bunların ne iş yaptıklarını da gövde kısmında yazabiliriz.
Daha kapsamlı bir örnek vermek gerekirse; farz edelim ki yukarıdaki örnekte bulunan Math
paketini kütüphane olarak tasarlıyoruz. Ve buna ek olarak, karmaşık sayıları gösteren Complex
adında bir tür tanımlamak istiyoruz. Fakat bu türün öğelerine direk erişimi de kısıtlamayı düşünüyoruz. O halde, Complex
türünü paketimizin private
kısmına yazabiliriz. Ayrıca Complex
türünden değişkenler üretmek ve bazı aritmetik işlemleri yapabilmek için de kimi fonksiyonları yazılımcının kullanımına açmayı istiyoruz. O zaman Math
kütüphanesi aşağıdaki gibi genişletilebilir ve başlık kısmı şu şekilde yazılabilir:
-- math.ads
package Math is
type Byte is mod 256;
PI : constant Float := 3.141_59;
E : constant Float := 2.718_28;
Catalan : constant Float := 0.915_96;
function Add (X, Y : Integer) return Integer;
function Sub (X, Y : Integer) return Integer;
function Mul (X, Y : Integer) return Integer;
function Div (X, Y : Integer) return Integer;
-- Complex türünün içeriğine erişim kısıtlı,
-- fakat bu türe ait değişken veya sabit oluşturulabilir
type Complex is private;
function Complex_Number (Re, Im : Float) return Complex;
function Re (Num : Complex) return Float;
function Im (Num : Complex) return Float;
function "+" (Left, Right : Complex) return Complex;
function "-" (Left, Right : Complex) return Complex;
private
type Complex is record
Re : Float := 0.0;
Im : Float := 0.0;
end record;
end Math;
Yukarıdaki kod içerisinde bulunan type Complex is private;
deyiminin amacı, kendisinden sonra gelen fonksiyonlarda Complex
türünü kullanabilmeye olanak sağlamak ve bunun yanında, Math
paketini kullanan birisinin Complex
türünden değişken veya sabit üretebilmesine de yardımcı olmak. Fakat bu türün öğelerine (yani Re
ve Im
) erişimin hala kısıtlı olduğu da unutulmamalı.
Math
paketinin gövde kısmı da aşağıdaki gibi yazılabilir:
-- math.adb
package body Math is
function Add (X, Y : Integer) return Integer is (X + Y);
function Sub (X, Y : Integer) return Integer is (X - Y);
function Mul (X, Y : Integer) return Integer is (X * Y);
function Div (X, Y : Integer) return Integer is (X / Y);
function Complex_Number (Re, Im : in Float) return Complex is ((Re, Im));
function Re (Num : Complex) return Float is (Num.Re);
function Im (Num : Complex) return Float is (Num.Im);
function "+" (Left, Right : Complex) return Complex is
((Left.Re + Right.Re, Left.Im + Right.Im));
function "-" (Left, Right : Complex) return Complex is
((Left.Re - Right.Re, Left.Im - Right.Im));
end Math;
Şimdi ufak bir uygulama içerisinde tüm fonksiyonları test edelim. Ve bu sayede yukarıda teorik olarak anlatılan with
ve use
anahtar kelimelerinin kullanımlarını ve etki alanlarını da görmüş oluruz.
-- main.adb
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Assertions; use Ada.Assertions;
with Math;
procedure Main is
begin
begin
Assert (Math.Add (3, 2) = 5, "Add fonksiyonu hatalı!");
Assert (Math.Sub (1, 2) = -1, "Sub fonksiyonu hatalı!");
Assert (Math.Mul (-3, -2) = 6, "Mul fonksiyonu hatalı!");
Assert (Math.Div (9, -2) = -4, "Div fonksiyonu hatalı!");
end;
declare
use Math;
X : Complex := Complex_Number (1.0, 2.0);
Y : Complex;
begin
Y := Complex_Number (0.0, 2.0);
Assert (Re (X) = 1.0, "Re fonksiyonu hatalı!");
Assert (Im (X) = 2.0, "Im fonksiyonu hatalı!");
Assert (Re (X + Y) = 1.0, "Re için + operatörü hatalı!");
Assert (Im (X + Y) = 4.0, "Im için + operatörü hatalı!");
Assert (Re (Y - X) = -1.0, "Re için - operatörü hatalı!");
Assert (Im (Y - X) = 0.0, "Im için - operatörü hatalı!");
end;
end Main;
Bir paket, içerisinde pek çok alt paketi de barındırabilir. Bu şekil bir kullanım, hiyerarşik bir paket yapısını elde etme olanağı da bizlere sağlar.
Şimdi, yukarıdaki kodda Complex
türü için Complex_Numbers
adında bir alt paket oluşturmayı düşünelim. Bu durumda Math
paketinin başlık kısmı şu hale gelecektir:
-- math.ads
package Math is
type Byte is mod 256;
PI : constant Float := 3.141_59;
E : constant Float := 2.718_28;
Catalan : constant Float := 0.915_96;
function Add (X, Y : Integer) return Integer;
function Sub (X, Y : Integer) return Integer;
function Mul (X, Y : Integer) return Integer;
function Div (X, Y : Integer) return Integer;
package Complex_Numbers is
type Complex is private;
function Complex_Number (Re, Im : Float) return Complex;
function Re (Num : Complex) return Float;
function Im (Num : Complex) return Float;
function "+" (Left, Right : Complex) return Complex;
function "-" (Left, Right : Complex) return Complex;
private
type Complex is record
Re : Float := 0.0;
Im : Float := 0.0;
end record;
end Complex_Numbers;
end Math;
Aynı şekilde, Math
paketinin gövdesi de aşağıdaki gibi olacaktır:
-- math.adb
package body Math is
function Add (X, Y : Integer) return Integer is (X + Y);
function Sub (X, Y : Integer) return Integer is (X - Y);
function Mul (X, Y : Integer) return Integer is (X * Y);
function Div (X, Y : Integer) return Integer is (X / Y);
package body Complex_Numbers is
function Complex_Number (Re, Im : in Float) return Complex is ((Re, Im));
function Re (Num : Complex) return Float is (Num.Re);
function Im (Num : Complex) return Float is (Num.Im);
function "+" (Left, Right : Complex) return Complex is
((Left.Re + Right.Re, Left.Im + Right.Im));
function "-" (Left, Right : Complex) return Complex is
((Left.Re - Right.Re, Left.Im - Right.Im));
end Complex_Numbers;
end Math;
Artık Complex
türüne ait fonksiyonlara Math.Complex_Numbers
üzerinden erişebiliriz. O halde, aşağıdaki örneğe dikkat edilirse, use Math;
deyimi değil, use Math.Complex_Number;
kullanılmış:
-- main.adb
...
declare
use Math.Complex_Numbers;
X : Complex := Complex_Number (1.0, 2.0);
Y : Complex;
begin
...
end;
...
Dikkat ederseniz Math
paketinin içeriği büyüdükçe satır sayısı da artıyor. Böyle bir paket içerisinde bir öğeyi aramak ve bulmak elbette ki zorlaşıyor. Zaten hiç bir yazılımcı da binlerce satırdan oluşan bir dosyayı okumak istemez :)
O halde, Math
paketi içerisinde bulunan Complex_Numbers
alt paketini ayırmak akla gelebilir. Ki şimdi yapacağımız şey de tam olarak budur. Tabii burada karşımıza yine dosya ismi için bir kural çıkmakta: bir alt paketin dosya adı, bulunduğu üst paketin adını içermeli ve ikisi arasında tire (-
) kullanılmalı. Şu halde, Complex_Numbers
için oluşturacağımız başlık ve gövde dosyaları math-complex_numbers.ads
ve math-complex_numbers.adb
olarak adlandırılacak. Şimdi, Complex_Numbers
alt paketi bu dosyalar içerisinde bulunacağı için, derleyiciye de bunu bildirmek gerekecek ve bundan sonra alt paketimiz Math.Complex_Numbers
olarak adlandırılacak. Üstelik ayrı dosya isimleri kullandığımızdan ötürü, Complex
türüne ve fonksiyonlarına with Math;
deyimi ile erişim sağlanamayacak. Artık alt paketin öğelerine erişebilmek için, örneğin main.adb
dosyası içerisinde ek olarak with Math.Complex_Numbers;
deyimi yazılacak. Yöntemin teorik kısmını anlattıktan sonra şimdi de Math
paketinin ve Math.Complex_Numbers
alt paketinin içeriklerine bir bakalım:
-- math.ads
package Math is
type Byte is mod 256;
PI : constant Float := 3.141_59;
E : constant Float := 2.718_28;
Catalan : constant Float := 0.915_96;
function Add (X, Y : Integer) return Integer;
function Sub (X, Y : Integer) return Integer;
function Mul (X, Y : Integer) return Integer;
function Div (X, Y : Integer) return Integer;
end Math;
-- math.adb
package body Math is
function Add (X, Y : Integer) return Integer is (X + Y);
function Sub (X, Y : Integer) return Integer is (X - Y);
function Mul (X, Y : Integer) return Integer is (X * Y);
function Div (X, Y : Integer) return Integer is (X / Y);
end Math;
Görüleceği gibi, Math
paketi içerisinde Complex
türüne ait hiç bir satır kalmamış; ve hepsi alt paketin dosyaları içerisine yazılmış:
-- math-complex_numbers.ads
package Math.Complex_Numbers is
type Complex is private;
function Complex_Number (Re, Im : Float) return Complex;
function Re (Num : Complex) return Float;
function Im (Num : Complex) return Float;
function "+" (Left, Right : Complex) return Complex;
function "-" (Left, Right : Complex) return Complex;
private
type Complex is record
Re : Float := 0.0;
Im : Float := 0.0;
end record;
end Math.Complex_Numbers;
-- math.complex_numbers.adb
package body Math.Complex_Numbers is
function Complex_Number (Re, Im : in Float) return Complex is ((Re, Im));
function Re (Num : Complex) return Float is (Num.Re);
function Im (Num : Complex) return Float is (Num.Im);
function "+" (Left, Right : Complex) return Complex is
((Left.Re + Right.Re, Left.Im + Right.Im));
function "-" (Left, Right : Complex) return Complex is
((Left.Re - Right.Re, Left.Im - Right.Im));
end Math.Complex_Numbers;
Şimdi, farz edelim ki yalnızca Complex_Numbers
alt paketi için bir test yazmak istiyoruz. O halde, örneğin complex_test.adb
adında bir dosya oluşturabilir ve bu alt pakete ait tüm testlerimizi buraya yazabiliriz:
-- complext_test.adb
with Ada.Assertions; use Ada.Assertions;
with Math.Complex_Numbers;
procedure complex_test is
use Math.Complex_Numbers;
X : Complex := Complex_Number (1.0, 2.0);
Y : Complex;
begin
Y := Complex_Number (0.0, 2.0);
Assert (Re (X) = 1.0, "Re fonksiyonu hatalı!");
Assert (Im (X) = 2.0, "Im fonksiyonu hatalı!");
Assert (Re (X + Y) = 1.0, "Re için + operatörü hatalı!");
Assert (Im (X + Y) = 4.0, "Im için + operatörü hatalı!");
Assert (Re (Y - X) = -1.0, "Re için - operatörü hatalı!");
Assert (Im (Y - X) = 0.0, "Im için - operatörü hatalı!");
end complex_test;
-- Derleme işlemi öncesi:
-- ❯ ls
-- complex_test.adb main.adb math-complex_numbers.adb math-complex_numbers.ads math.adb math.ads
-- Derleme işlemi:
-- ❯ gnatmake complex_test.adb
-- gcc -c complex_test.adb
-- gcc -c math.adb
-- gcc -c math-complex_numbers.adb
-- gnatbind -x complex_test.ali
-- gnatlink complex_test.ali
-- Derleme işlemi sonrası:
-- ❯ ls
-- complex_test* complex_test.ali main.adb math-complex_numbers.ads math-complex_numbers.o math.ads math.o
-- complex_test.adb complex_test.o math-complex_numbers.adb math-complex_numbers.ali math.adb math.ali
Yukarıdaki derleme işleminden de anlaşılacağı üzere, her ne kadar complex_test.adb
dosyası içerisinde yalnızca Math.Complex_Numbers
alt paketini kullanmış olsak da derleyici tüm paketi derlemiş. Bu noktada şunu söyleyebiliriz: her bir alt paket aslında ayrı ayrı derlenir. Fakat en nihayetinde en üst pakete ihtiyaç vardır. Bu sayede Math
paketi için bir obje dosyası oluşturulur (math.o
). Farklı bir şekilde anlatmak gerekirse; math.ads
dosyası olmadan math-complex_numbers.ads
ve math-complex_numbers.adb
dosyaları derlenmez. En azından, aşağıdaki gibi boş dahi olsa bir math.ads
dosyasına kesinlikle ihtiyaç vardır.
-- math.ads
package Math is
end Math;
Şimdi görüş açımızı biraz daha genişletelim ve yukarıdaki Math
kütüphanesini büyütelim. Farz edelim ki geometrik işlemler için Math.Geometry
adında bir alt pakete ihtiyacımız var. Aynı şekilde cebirsel işlemler için de Math.Algebra
adında bir tane alt paket oluşturacağız. O halde, Complex_Numbers
da cebir ile alakalı olduğu için Math.Algebra
içerisinde bir alt paket olarak bulunacak. Şimdi Math
paketinin ve alt paketlerinin başlık ve gövde dosyalarına sırasıyla bi bakalım:
-- math.ads
package Math is
type Byte is mod 256;
PI : constant Float := 3.141_59;
E : constant Float := 2.718_28;
Catalan : constant Float := 0.915_96;
Counter : Integer := 0;
end Math;
Görüleceği gibi math.ads
dosyası içerisinde Byte
türümüz ve sabitlerimiz bulunuyor. Ayrıca ek olarak bir de Counter
adında değişken tanımlamışız. Add
, Sub
, Mul
ve Div
alt programları cebirsel işlemler olduğu için Math.Algebra
alt paketi içerisine yazdık.
-- math-algebra.ads
package Math.Algebra is
function Add (X, Y : Integer) return Integer is (X + Y);
function Sub (X, Y : Integer) return Integer is (X - Y);
function Mul (X, Y : Integer) return Integer is (X * Y);
function Div (X, Y : Integer) return Integer is (X / Y);
Counter : Integer := Math.Counter;
end Math.Algebra;
Add
, Sub
, Mul
ve Div
alt programları basit birer fonksiyon olduğundan ötürü, bu fonksiyonların içerikleri math-algebra.ads
dosyası içerisinde yazılmış. Demek oluyor ki, math-algebra.adb
adında bir dosyaya ihtiyacımız olmayacak. Sonrasında Counter
adında bir değişken tanımlanmış. Hatırlarsanız aynı isimde olan bir değişkeni math.ads
dosyası içerisinde de tanımlamıştık. Fakat bu iki değişken herhangi bir çakışma oluşturmaz çünkü alt paketler de kendilerine ait bir alan adını (namespace) beraberinde getirirler. O halde diyebiliriz ki; Math.Counter
ile Math.Algebra.Counter
değişkenleri esasında birbirlerinden farklı değişkenlerdir.
-- math-algebra-complex_numbers.ads
package Math.Algebra.Complex_Numbers is
type Complex is private;
function Complex_Number (Re, Im : Float) return Complex;
function Re (Num : Complex) return Float;
function Im (Num : Complex) return Float;
function "+" (Left, Right : Complex) return Complex;
function "-" (Left, Right : Complex) return Complex;
private
type Complex is record
Re : Float := 0.0;
Im : Float := 0.0;
end record;
end Math.Algebra.Complex_Numbers;
-- math-algebra-complex_numbers.adb
package body Math.Algebra.Complex_Numbers is
function Complex_Number (Re, Im : in Float) return Complex is ((Re, Im));
function Re (Num : Complex) return Float is (Num.Re);
function Im (Num : Complex) return Float is (Num.Im);
function "+" (Left, Right : Complex) return Complex is
((Left.Re + Right.Re, Left.Im + Right.Im));
function "-" (Left, Right : Complex) return Complex is
((Left.Re - Right.Re, Left.Im - Right.Im));
end Math.Algebra.Complex_Numbers;
Yukarıdaki alt paketin adına dikkat edilirse Math.Algebra.Complex_Numbers
olarak verilmiş; çünkü bu alt paketin Algebra
içerisinde bulunacağını belirtmiştik. Aynı şekilde Algebra
da Math
paketi içerisinde bulunuyor. Bundan ötürü, Math.Algebra.Complex_Numbers
alt paketinin başlık dosyası math-algebra-complex_numbers.ads
, gövde dosyası ise math-algebra-complex_numbers.adb
olarak adlandırılmış. Yani demek oluyor ki, hiyerarşik bir paket sisteminde her bir alt pakete ait dosya adları, kendisinin bulunduğu tüm üst paketlerin isimlerini içerisinde barındırır; ve her biri tire (-
) işareti kullanılarak ayrılır.
Son olarak Geometry
alt paketini de yazalım. Farz edelim ki bu alt paket de bazı basit fonksiyonları içerisinde barındırıyor. Örneğin dairenin alanını hesaplayan bir fonksiyon: Circle_Area
. O halde bu alt paketin başlık dosyası şu şekilde olacak:
-- math-geometry.ads
package Math.Geometry is
function Circle_Area (R : Float) return Float is (PI * R * R);
end Math.Geometry;
Şimdi de tüm değişkenleri ve fonksiyonları test etmek istiyoruz ve aşağıdaki gibi main.adb
dosyası oluşturuyoruz:
-- main.adb
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Assertions; use Ada.Assertions;
with Math.Geometry;
with Math.Algebra;
with Math.Algebra.Complex_Numbers;
procedure Main is
begin
Math.Counter := 1;
Put_Line ("Math.Counter: " & Math.Counter'Image);
Math.Algebra.Counter := 10;
Put_Line ("Math.Algebra.Counter: " & Math.Algebra.Counter'Image);
declare
use Math.Algebra;
begin
Assert (Add (3, 2) = 5, "Add fonksiyonu hatalı!");
Assert (Sub (1, 2) = -1, "Sub fonksiyonu hatalı!");
Assert (Mul (-3, -2) = 6, "Mul fonksiyonu hatalı!");
Assert (Div (9, -2) = -4, "Div fonksiyonu hatalı!");
end;
declare
use Math;
begin
Assert (Geometry.Circle_Area (1.0) = Math.PI, "Alan hesaplama hatalı!");
end;
declare
use Math.Algebra.Complex_Numbers;
X : Complex := Complex_Number (1.0, 2.0);
Y : Complex;
begin
Y := Complex_Number (0.0, 2.0);
Assert (Re (X) = 1.0, "Re fonksiyonu hatalı!");
Assert (Im (X) = 2.0, "Im fonksiyonu hatalı!");
Assert (Re (X + Y) = 1.0, "Re için + operatörü hatalı!");
Assert (Im (X + Y) = 4.0, "Im için + operatörü hatalı!");
Assert (Re (Y - X) = -1.0, "Re için - operatörü hatalı!");
Assert (Im (Y - X) = 0.0, "Im için - operatörü hatalı!");
end;
end Main;
Dikkat ederseniz main.adb
dosyası içerisinde, öğesine erişilmek istenen tüm dosyalar with
anahtar kelimesi ile yazılmış. Diyelim ki biz sadece with Algebra;
yazarak Comlex_Numbers
alt paketine de erişmek istiyoruz. O halde math-algebra.ads
dosyası içerisinde aşağıdaki satır eklenir:
limited with Math.Algebra.Complex_Numbers;
Ada dilinde bulunan limited
anahtar kelimesi pek çok yerde ve farklı anlamlarda karşımıza çıkar. Buraki manası ise ileride tanımlanacak olan bir alt paket ile yapılan bağlantıyı ifade eder. Yani, bizim örneğimiz üzerinden anlatmak gerekirse; Math.Algebra
alt paketi içerisinde bulunan limited
anahtar kelimesi, ileride tanımlanacak olan Math.Algebra.Complex_Numbers
alt paketine bağımlı ve Complex_Numbers
içerisinde bulunan bazı öğeler Algebra
içerisinde kullanılacak anlamına gelir.
Özel Alt Paketler
Bir alt paketi, bulunduğu paketin dışarısından erişimine tamamen kapatmak için private package
deyimi kullanılır. Örneğin, Math
kütüphanesinde bulunan sabitleri Math.Constant
içerisinde tanımlamak ve bu sabitleri dışarıdan erişimini kısıtlamak istiyoruz. O halde kütüphanemiz içerisinde aşağıdaki gibi math-constants.ads
adında bir dosya oluşturabiliriz:
-- math-constants.ads
package Math.Constants is
PI : constant Float := 3.141_59;
E : constant Float := 2.718_28;
Catalan : constant Float := 0.915_96;
end Math.Constants;
Bu durumda Math.Geometry
alt paketi için bir gövde de yazılmalı:
-- math-geometry.adb
with Math.Constants;
package body Math.Geometry is
function Circle_Area (R : Float) return Float is (Math.Constants.PI * R * R);
end Math.Geometry;
Bu sayede main.adb
içerisinde, örneğin yukarıdaki gibi PI
sabitine erişim kesinlikle gerçekleşmez.
Bitirirken
Ada programlama dilinde paket kullanımının çok kapsamlı olduğuna değinmiştik. Makalemizin daha anlaşılır olması için uzun uzun örneklere yer verildi. Ayrıca paket konusunun burada bitmediğini belirtmekte fayda var. Çünkü nesne yönelimli programlama tekniklerini yine paketler yardımıyla gerçekleştireceğiz.