Bagian generic pada unit generik dapat memuat lebih dari satu jenis parameter formal (formal parameter), yaitu tipe berkendala, subprogram, dan package. Kendala yang dituliskan pada parameter formal menentukan operasi apa saja yang tersedia di dalam badan generik dan tipe aktual apa saja yang sah saat instansiasi. Topik ini membahas ragam kendala tipe formal, penyuntikan operasi melalui parameter formal subprogram, penyuntikan package melalui parameter formal package, serta kesalahan instansiasi yang sering terjadi. Contoh yang digunakan adalah pengurutan pembacaan sensor suhu dengan dua kriteria urutan yang berbeda.
Ragam kendala pada tipe formal#
Tipe formal berkendala dinyatakan dengan bentuk yang menjamin operasi minimal di dalam badan generik. Semakin kaya kendalanya, semakin banyak operasi yang dapat digunakan secara bebas, tetapi semakin sempit pula daftar tipe aktual yang sah. Tabel berikut merangkum bentuk yang sering digunakan beserta jaminannya.
| Bentuk tipe formal | Jaminan di dalam badan generik | Contoh tipe aktual |
|---|---|---|
type T is private | penugasan, salinan, dan kesamaan | Integer, record apa pun |
type T is limited private | tanpa penugasan, untuk tipe limited | tipe dengan sumber daya eksternal |
type T is range <> | operator bilangan bulat dan atribut rentang | Integer dan tipe range |
type T is mod <> | operator bilangan bulat tak bertanda | Ada.Containers.Hash_Type |
type T is digits <> | operator titik mengambang | Float |
type T is (<> ) | tipe diskrit beserta atributnya | tipe diskrit apa pun |
Bentuk is limited private menjamin lebih sedikit operasi daripada is private, yaitu penugasan antarobjek dihilangkan, sehingga tipe limited juga dapat menjadi tipe aktualnya. Bentuk is range <> dan is mod <> menjamin seluruh operator aritmetika bilangan bulat, sedangkan is digits <> menjamin aritmetika titik mengambang seperti yang digunakan pada contoh rata-rata suhu. Karena itu, pemilihan kendala merupakan keputusan rancangan: kendala ditulis seketat kebutuhan operasi di dalam badan generik.
Kendala is (<> ) sering membingungkan karena notasi (<> ) tidak menyebut kendala apa pun secara eksplisit. Notasi (<> ) berarti tipe diskrit apa pun diterima tanpa kendala tambahan, sehingga badan generik dapat menulis perulangan for Hari in T'Range atau menggunakan atribut enumerasi tanpa mengetahui nama tipe aktualnya. Bentuk is range <> mencakup seluruh tipe bilangan bulat bertanda, sedangkan is mod <> membatasi pada tipe modular yang aritmetikanya melingkar.
Parameter formal subprogram#
Parameter formal subprogram dinyatakan dengan kata with function atau with procedure, lalu diisi dengan subprogram nyata saat instansiasi. Bentuk inilah yang mengatasi kesalahan operator pada tipe formal is private, yaitu operasi yang tidak dijamin kendala tetap dapat digunakan selama disuntikkan sebagai parameter. Program berikut mengurutkan array suhu dengan prosedur generik yang kriteria urutannya disuntikkan melalui parameter formal subprogram.
with Ada.Text_IO;
with Ada.Float_Text_IO;
procedure Uji_Urutkan is
type Larik_Suhu is array (Positive range <>) of Float;
-- Parameter formal subprogram: kriteria urutan disuntikkan.
generic
type T is private;
type Larik is array (Positive range <>) of T;
with function Lebih_Dulu (Kiri, Kanan : T) return Boolean;
procedure Urutkan (Daftar : in out Larik);
procedure Urutkan (Daftar : in out Larik) is
Sementara : T;
begin
for I in Daftar'Range loop
for J in I + 1 .. Daftar'Last loop
if Lebih_Dulu (Daftar (J), Daftar (I)) then
Sementara := Daftar (I);
Daftar (I) := Daftar (J);
Daftar (J) := Sementara;
end if;
end loop;
end loop;
end Urutkan;
procedure Urutkan_Naik is new Urutkan
(T => Float, Larik => Larik_Suhu, Lebih_Dulu => "<");
procedure Urutkan_Turun is new Urutkan
(T => Float, Larik => Larik_Suhu, Lebih_Dulu => ">");
procedure Cetak (Judul : String; Daftar : Larik_Suhu) is
begin
Ada.Text_IO.Put (Judul & " :");
for Nilai of Daftar loop
Ada.Text_IO.Put (" ");
Ada.Float_Text_IO.Put (Nilai, Fore => 1, Aft => 2, Exp => 0);
end loop;
Ada.Text_IO.New_Line;
end Cetak;
Suhu : Larik_Suhu := (22.5, 21.5, 23.5, 22.0);
begin
Urutkan_Naik (Suhu);
Cetak ("Urutan naik", Suhu);
Suhu := (22.5, 21.5, 23.5, 22.0);
Urutkan_Turun (Suhu);
Cetak ("Urutan turun", Suhu);
end Uji_Urutkan;# kompilasi program
gnatmake -q uji_urutkan.adb
# jalankan program
./uji_urutkanUrutan naik : 21.50 22.00 22.50 23.50
Urutan turun : 23.50 22.50 22.00 21.50Keluaran memperlihatkan dua urutan dari satu badan prosedur yang sama, yaitu naik melalui operator < dan turun melalui operator >. Asosiasi Lebih_Dulu => "<" menunjukkan bahwa operator juga dapat menjadi aktual untuk parameter formal subprogram, sepanjang tanda tangannya (signature) cocok. Parameter formal subprogram boleh diberi nilai bawaan dengan bentuk is <>, sehingga instansiasi boleh mengabaikannya apabila subprogram bernama sama sudah terlihat di tempat instansiasi. Pola ini digunakan secara luas pada library standar, misalnya untuk memasok fungsi hash pada container.
Kesesuaian tanda tangan menjadi syarat mutlak pada parameter formal subprogram, yaitu tipe parameter, mode, dan tipe kembalian harus cocok dengan deklarasi formalnya. Aktual berupa operator seperti < diperiksa dengan aturan yang sama, sehingga operator yang tipe operannya berbeda akan ditolak. Aturan ini menjaga keamanan tipe subprogram generik, karena seluruh operasi yang disuntikkan telah diperiksa tipenya pada waktu kompilasi.
Parameter formal package#
Parameter formal package dinyatakan dengan with package beserta pola instansiasi yang menjadi acuan package aktual. Mekanisme ini menyuntikkan seluruh isi package aktual ke dalam unit generik, sehingga generik dapat membangun di atas package lain tanpa mengetahui tipe yang digunakan instansiasi tersebut. Pola (<> ) pada posisi parameter instansiasi berarti instansiasi apa pun diterima.
-- tidak-dijalankan
generic
with package Sekumpulan is new Ada.Containers.Vectors (<>);
package Analisis_Vector is
function Rata_Rata (V : Sekumpulan.Vector) return Float;
end Analisis_Vector;Pada kerangka di atas, package Analisis_Vector menerima instansiasi Ada.Containers.Vectors apa pun sebagai aktualnya, kemudian menggunakan tipe Vector dari instansiasi itu pada spesifikasinya. Bentuk semacam ini menghindari penulisan ulang parameter formal yang panjang, karena seluruh parameter instansiasi diwariskan sekaligus melalui package formalnya. Klien cukup menginstansiasi Analisis_Vector dengan instansiasi vector yang sudah ada, dan kedua package itu tetap konsisten karena polanya sama.
Apabila parameter instansiasi perlu dikendalikan, pola (<> ) dapat diganti dengan daftar parameter yang menyebut bagian yang wajib cocok. Bentuk daftar semacam ini menjaga konsistensi antarunit, misalnya memastikan seluruh analisis menggunakan vector dengan tipe indeks yang sama. Sisanya tetap bebas diisi oleh setiap instansiasi, sehingga kendali dan keluwesan dapat diseimbangkan.
Kesalahan umum#
Kesalahan instansiasi yang sering terjadi adalah memberikan tipe aktual yang tidak memenuhi kendala parameter formalnya. Contoh berikut menginstansiasi tipe formal is range <>, yang hanya menerima bilangan bulat bertanda, dengan tipe Float.
-- Berkas ini sengaja salah: menginstansiasi tipe formal range dengan Float.
procedure Instansiasi_Float_Error is
generic
type T is range <>;
function Ganda (Nilai : T) return T;
function Ganda (Nilai : T) return T is
begin
return Nilai * 2;
end Ganda;
function Ganda_Float is new Ganda (T => Float);
begin
null;
end Instansiasi_Float_Error;# kompilasi berkas yang menginstansiasi tipe formal range dengan Float
gnatmake -q instansiasi_float_error.adbinstansiasi_float_error.adb:13:44: error: expect signed integer type in instantiation of "T"
instansiasi_float_error.adb:13:44: error: instantiation abandoned
gnatmake: "instansiasi_float_error.adb" compilation errorPesan error menyatakan bahwa tipe aktual yang diharapkan adalah bilangan bulat bertanda (signed integer), sebab kendala is range <> menjamin aritmetika bilangan bulat di dalam badan generik. Perbaikannya adalah mengganti tipe aktual menjadi tipe bilangan bulat, misalnya Integer, atau melonggarkan kendala menjadi is digits <> apabila tipe titik mengambang memang dikehendaki. Kesalahan serupa muncul pula apabila parameter formal subprogram tanpa nilai bawaan tidak diberi aktual saat instansiasi, sehingga setiap parameter formal wajib diperiksa sebelum unit generik diinstansiasi.
Ringkasan#
- Tipe formal berkendala menjamin operasi minimal di dalam badan generik, dan kendala yang lebih ketat menerima lebih sedikit tipe aktual.
- Parameter formal subprogram dengan
with functionmenyuntikkan operasi seperti operator perbandingan pada saat instansiasi. - Parameter formal package dengan
with package ... is new ... (<> )menyuntikkan seluruh isi instansiasi package lain tanpa menyebut tipe aktualnya.
Referensi#
- Ada Reference Manual 2022, Bagian 12.5 Formal Types — Ada Resource Association — Menetapkan ragam tipe formal beserta kendalanya, dari private hingga bilangan bulat dan titik mengambang.
- Ada Reference Manual 2022, Bagian 12.6 Formal Subprograms — Ada Resource Association — Menetapkan aturan parameter formal subprogram beserta nilai bawaannya.
- Ada Reference Manual 2022, Bagian 12.7 Formal Packages — Ada Resource Association — Menetapkan bentuk parameter formal package dan pola instansiasinya.