Subtipe dan tipe turunan

Perbedaan subtipe sebagai tampilan terkendala dan tipe turunan sebagai tipe baru yang sesungguhnya.

Daftar isi

Sebuah tipe yang sudah ada dapat dipersempit tanpa membuat tipe baru, dan dapat dijadikan induk bagi tipe yang benar-benar terpisah. Kedua jalur ini berbeda tujuan dan berbeda akibat: subtype adalah tampilan terkendala dari tipe yang sama, sedangkan derived type adalah tipe baru yang mewarisi operasi induknya. Topik ini membedakan keduanya melalui tipe Tegangan, dengan pemeriksaan yang dijalankan pada waktu kompilasi maupun waktu berjalan.

Subtype sebagai tampilan terkendala#

Subtype dideklarasikan dengan kata subtype, nama baru, tipe induk, dan kendala opsional. Subtype tidak memperkenalkan tipe baru, sehingga nilai dari subtype dan tipe induknya saling dipertukarkan tanpa konversi eksplisit. Subtype tanpa kendala juga sah dan digunakan untuk memberi nama yang lebih bermakna pada tipe yang sama. Subtype dengan kendala mempersempit himpunan nilai yang sah, dan kendala itu diperiksa pada setiap penugasan nilai baru ke objek bertipe subtype.

ada Contoh: deklarasi subtype dengan dan tanpa kendala
-- tidak-dijalankan
type Tegangan is range 0 .. 240;
subtype Tegangan_Aman is Tegangan range 210 .. 230;
subtype Tegangan_Bebas is Tegangan;

Kendala pada Tegangan_Aman menyatakan bahwa hanya nilai 210 hingga 230 yang sah untuk objek bertipe subtype tersebut, padahal tipe induknya menerima 0 hingga 240. Kedua subtype menggunakan representasi yang sama dengan Tegangan, sehingga tidak ada penyalinan ataupun konversi yang dilakukan saat keduanya dipertukarkan. Pemeriksaan kendala bekerja pada penugasan, inisialisasi, dan pengiriman parameter, yaitu saat-saat nilai baru masuk ke objek bertipe subtype. Tidak ada biaya waktu eksekusi tambahan karena tidak ada data baru yang dibuat.

Subtype juga dapat diturunkan dari subtype lain, dan kendala keduanya berlaku serentak. Subtype seperti subtype Tegangan_Uji is Tegangan_Aman range 215 .. 220; hanya menerima nilai yang memenuhi kendala induknya sekaligus kendala tambahannya, sehingga kendala yang saling berlapis tidak perlu ditulis ulang dari awal. Subtype tanpa kendala yang disebut pada contoh sebelumnya memiliki peran lain, yaitu memberi nama domain pada tipe yang sama tanpa mengubah himpunan nilainya, dan penamaan semacam ini membuat deklarasi objek lebih mudah dibaca.

Pemeriksaan kendala pada penugasan#

Program berikut menugaskan nilai 225 yang sah ke objek bertipe Tegangan_Aman, menyalinnya ke variabel bertipe induk tanpa konversi, kemudian menugaskan nilai 240 yang berada di luar kendala subtype.

ada subtipe_error.adb
with Ada.Text_IO;

procedure Subtipe_Error is
   type Tegangan is range 0 .. 240;
   subtype Tegangan_Aman is Tegangan range 210 .. 230;

   T : Tegangan;
   S : Tegangan_Aman;
begin
   S := 225;
   T := S;
   Ada.Text_IO.Put_Line (Tegangan'Image (T));
   S := 240;
   Ada.Text_IO.Put_Line (Tegangan_Aman'Image (S));
end Subtipe_Error;
bash
# kompilasi lalu jalankan program yang melanggar kendala subtype
gnatmake -q subtipe_error.adb
./subtipe_error
text Keluaran
subtipe_error.adb:13:09: warning: value not in range of type "Tegangan_Aman" defined at line 5 [enabled by default]
subtipe_error.adb:13:09: warning: Constraint_Error will be raised at run time [enabled by default]
 225

raised CONSTRAINT_ERROR : subtipe_error.adb:13 range check failed

Baris peringatan menyebut kendala Tegangan_Aman beserta baris definisinya, sedangkan pesan terakhir menyebut pemeriksaan rentang (range check) pada baris penugasan yang melanggar. Nilai 240 sah menurut tipe induk Tegangan, tetapi ditolak pemeriksaan kendala karena objek penerima bertipe subtype yang lebih sempit. Nilai 225 yang sah sempat dicetak sebelum kegagalan, sehingga urutan eksekusi tetap dapat dilacak dari keluaran. Pelanggaran kendala subtype dilempar sebagai Constraint_Error, sama seperti pelanggaran rentang pada tipe induknya.

Tipe turunan sebagai tipe baru#

Tipe turunan dideklarasikan dengan kata type dan kata new yang diikuti tipe induk. Definisi type Tegangan_Volt is new Tegangan; memperkenalkan tipe yang benar-benar baru: nilainya tidak saling dipertukarkan dengan nilai Tegangan tanpa konversi eksplisit, meskipun rentang dan seluruh operasinya diwariskan. Konversi antar tipe yang berhubungan ditulis dengan nama tipe tujuan sebagai fungsi, contohnya Tegangan_Volt (T) dan Tegangan (V). Operator yang diwariskan bekerja antar nilai sesama tipe turunan tanpa konversi tambahan.

Tipe turunan juga boleh mempersempit rentang pada deklarasinya, misalnya type Tegangan_Kritis is new Tegangan range 0 .. 15;. Tipe baru itu tetap mewarisi operasi induknya, tetapi nilai yang sah terbatas pada rentang yang dituliskan. Rentang tipe turunan tidak mungkin lebih luas daripada rentang induknya, karena seluruh nilai turunan wajib menjadi nilai sah induknya pula. Dengan dua kemampuan ini, tipe turunan digunakan untuk domain yang berbeda sekaligus domain yang lebih sempit, sedangkan pertukaran nilai dengan tipe induknya tetap menuntut konversi eksplisit.

ada turunan_ok.adb
with Ada.Text_IO;

procedure Turunan_Ok is
   type Tegangan is range 0 .. 240;
   type Tegangan_Volt is new Tegangan;

   T : Tegangan      := 230;
   V : Tegangan_Volt := Tegangan_Volt (T);
begin
   V := V + Tegangan_Volt (10);
   Ada.Text_IO.Put_Line (Tegangan_Volt'Image (V));
   T := Tegangan (V);
   Ada.Text_IO.Put_Line (Tegangan'Image (T));
end Turunan_Ok;
bash
# kompilasi program dengan konversi eksplisit
gnatmake -q turunan_ok.adb
# jalankan program
./turunan_ok
text Keluaran
 240
 240

Program di atas mengonversi Tegangan menjadi Tegangan_Volt secara eksplisit, menjumlahkannya dengan nilai sesama tipe turunan, kemudian mengonversi hasilnya kembali ke tipe asal. Seluruh konversi tertulis pada program, sehingga tipe setiap operasi terbaca tanpa menebak. Bentuk konversi ini menjadi satu-satunya cara untuk menukar nilai antara kedua tipe, dan penulisan tanpa konversi ditolak kompilator. Program berikut sengaja menghilangkan konversi pada operasi penjumlahan yang mencampur kedua tipe.

ada turunan_error.adb
with Ada.Text_IO;

procedure Turunan_Error is
   type Tegangan is range 0 .. 240;
   type Tegangan_Volt is new Tegangan;

   T : Tegangan      := 230;
   V : Tegangan_Volt := Tegangan_Volt (230);
begin
   T := T + V;
   Ada.Text_IO.Put_Line (Tegangan'Image (T));
end Turunan_Error;
bash
# mencoba mengompilasi program yang mencampur dua tipe
gnatmake -q turunan_error.adb
text Keluaran
turunan_error.adb:10:11: error: invalid operand types for operator "+"
turunan_error.adb:10:11: error: left operand has type "Tegangan" defined at line 4
turunan_error.adb:10:11: error: right operand has type "Tegangan_Volt" defined at line 5
gnatmake: "turunan_error.adb" compilation error

Kompilator menolak programnya dan menyebut kedua tipe yang berbeda pada tiga baris pesan error. Operator + menerima operan kiri bertipe Tegangan dan operan kanan bertipe Tegangan_Volt, dan tidak ada operator untuk kombinasi itu. Penolakan terjadi pada waktu kompilasi, sehingga kekeliruan pencampuran tipe tidak pernah membawa hasil salah ke dalam perhitungan.

Memilih antara subtype dan tipe turunan#

Subtype dipilih apabila nilai-nilainya tetap berada dalam satu domain yang sama dan saling dipertukarkan, contohnya batas operasi aman sebuah alat ukur. Tipe turunan dipilih apabila domainnya berbeda dan kekeliruan pencampuran harus ditolak sejak waktu kompilasi, contohnya tegangan dalam volt dan tegangan dalam satuan internal konverter. Tabel berikut merangkum perbedaan keduanya.

Aspeksubtypetipe turunan
Identitas tipesama dengan tipe induktipe baru yang berdiri sendiri
Pertukaran nilai dengan tipe induktanpa konversi, kendala diperiksawajib konversi eksplisit
Operasiseluruh operasi tipe indukoperasi yang diwariskan pada deklarasi
Tempat pemeriksaankendala pada setiap penugasankecocokan tipe pada waktu kompilasi

Ringkasan#

  • Subtype adalah tampilan terkendala dari tipe yang sama, dan nilainya dipertukarkan dengan tipe induk tanpa konversi.
  • Kendala subtype diperiksa pada setiap penugasan, dan pelanggarannya melempar Constraint_Error dengan pesan range check.
  • Tipe turunan adalah tipe baru yang mewarisi operasi induknya, dan pencampuran nilainya tanpa konversi ditolak pada waktu kompilasi.

Referensi#