Enumerasi

Tipe enumerasi dengan nilai buatan pengguna serta atribut Pos dan Val untuk konversi.

Daftar isi

Tipe enumerasi (enumeration) memperkenalkan sekumpulan nilai baru yang ditentukan sendiri oleh pembuat program, bukan angka yang diberi nama lain. Topik ini membahas deklarasi tipe enumeration, konversi melalui atribut Pos dan Val, konversi teks melalui atribut Image dan Value, serta pernyataan case yang wajib mencakup seluruh nilai. Contoh yang digunakan adalah arah mata angin dan status mesin, dengan keluaran yang diambil langsung dari eksekusi nyata.

Tipe enumeration serta atribut Pos dan Val#

Deklarasi enumeration menyebutkan seluruh literal pembentuk tipe di dalam kurung, dipisahkan oleh koma. Definisi type Arah is (Utara, Timur, Selatan, Barat); memperkenalkan empat literal yang menjadi konstanta milik tipe Arah. Setiap literal memperoleh nomor posisi menurut urutannya pada deklarasi, dimulai dari nol. Atribut Pos mengubah literal menjadi nomor posisinya, sedangkan atribut Val mengubah nomor posisi kembali menjadi literal.

ada arah.adb
with Ada.Text_IO;

procedure Arah is
   type Arah is (Utara, Timur, Selatan, Barat);
begin
   Ada.Text_IO.Put_Line (Arah'Image (Arah'First));
   Ada.Text_IO.Put_Line (Integer'Image (Arah'Pos (Timur)));
   Ada.Text_IO.Put_Line (Arah'Image (Arah'Val (2)));
   Ada.Text_IO.Put_Line (Arah'Image (Arah'Value ("barat")));
   for A in Arah loop
      Ada.Text_IO.Put_Line (Integer'Image (Arah'Pos (A))
                            & " = " & Arah'Image (A));
   end loop;
end Arah;
bash
# kompilasi program
gnatmake -q arah.adb
# jalankan program
./arah
text Keluaran
UTARA
 1
SELATAN
BARAT
 0 = UTARA
 1 = TIMUR
 2 = SELATAN
 3 = BARAT

Atribut Image pada baris pertama mengubah literal Utara menjadi teks UTARA dengan huruf besar. Pemanggilan Arah'Val (2) menghasilkan literal ketiga sesuai urutan deklarasi, dan string "barat" yang ditulis dengan huruf kecil tetap diterima atribut Value karena pencocokannya tidak peka huruf besar-kecil. Perulangan for A in Arah menelusuri seluruh nilai tipe dari posisi pertama hingga terakhir, sehingga tidak ada literal yang terlewat. Urutan pada deklarasi menjadi urutan resmi tipe, dan atribut First serta Last mengikuti urutan yang sama.

Urutan itu juga menjadi dasar bagi dua atribut lagi yang sering digunakan, yaitu Succ dan Pred. Atribut Succ menghasilkan literal sesudahnya, sedangkan Pred menghasilkan literal sebelumnya. Pemanggilan Pred terhadap First atau Succ terhadap Last melempar Constraint_Error karena tidak ada literal yang dituju. Selain itu, dua tipe enumeration yang berbeda boleh mendeklarasikan literal dengan nama yang sama, dan kompilator menentukan maknanya dari konteks penggunaan. Apabila konteks tidak cukup untuk membedakan, penulisan yang menyebut tipe secara eksplisit seperti Arah'Utara menyelesaikannya.

Konversi teks yang gagal#

Atribut Value menerima string dan menghasilkan literal yang cocok, tetapi tidak selalu ada literal yang cocok untuk string yang diberikan. Apabila tidak ada yang cocok, Value melempar Constraint_Error dengan pesan yang menyebut string pemicunya. Program berikut meminta literal untuk string LAUT yang bukan anggota tipe Arah.

ada nilai_error.adb
with Ada.Text_IO;

procedure Nilai_Error is
   type Arah is (Utara, Timur, Selatan, Barat);
   A : Arah;
begin
   A := Arah'Value ("LAUT");
   Ada.Text_IO.Put_Line (Arah'Image (A));
end Nilai_Error;
bash
# kompilasi lalu jalankan program dengan string tidak sah
gnatmake -q nilai_error.adb
./nilai_error
text Keluaran
raised CONSTRAINT_ERROR : bad input for 'Value: "LAUT"

Pesan bad input for 'Value menyebut string yang gagal diproses, sehingga penyebabnya terbaca langsung dari keluaran tanpa menelusuri kode. Pemanggilan Value dengan string yang berasal dari luar program, misalnya argumen baris perintah atau berkas konfigurasi, perlu disertai penanganan exception agar masukan yang salah tidak menghentikan program. Konversi yang sah seperti "barat" pada program sebelumnya menunjukkan bahwa perbedaan huruf besar-kecil tidak menjadi kendala. Pemeriksaan keanggotaan tetap ketat, dan string yang bukan literal mana pun pasti ditolak.

Pernyataan case yang wajib lengkap#

Pernyataan case memilih satu cabang menurut nilai sebuah ekspresi, dan bahasa menuntut agar seluruh nilai yang mungkin tercakup oleh cabang yang ada. Tuntutan ini diperiksa pada waktu kompilasi, sehingga penambahan literal baru pada tipe otomatis menandai setiap case yang belum mencakupnya. Program berikut sengaja menghilangkan satu literal dari pernyataan case yang dimuatnya.

ada status_kasus.adb
with Ada.Text_IO;

procedure Status_Kasus is
   type Status is (Matikan, Siap, Beroperasi);
   S : Status := Siap;
begin
   case S is
      when Matikan =>
         Ada.Text_IO.Put_Line ("mesin mati");
      when Siap =>
         Ada.Text_IO.Put_Line ("mesin siap");
   end case;
end Status_Kasus;
bash
# mencoba mengompilasi program dengan case tidak lengkap
gnatmake -q status_kasus.adb
text Keluaran
status_kasus.adb:7:04: error: missing case value: "Beroperasi"
gnatmake: "status_kasus.adb" compilation error

Pesan error menyebut persis literal yang belum tercakup, yaitu Beroperasi. Perbaikannya adalah menambahkan cabang untuk literal tersebut, dan program lolos kompilasi setelah seluruh nilai tercakup.

ada Contoh: pernyataan case yang mencakup seluruh literal
-- tidak-dijalankan
case S is
   when Matikan =>
      Ada.Text_IO.Put_Line ("mesin mati");
   when Siap =>
      Ada.Text_IO.Put_Line ("mesin siap");
   when Beroperasi =>
      Ada.Text_IO.Put_Line ("mesin beroperasi");
end case;

Kelengkapan otomatis seperti ini adalah bentuk lain dari pengetikan kuat: perubahan pada definisi tipe langsung menandai setiap titik yang menggunakan tipe tersebut. Pada bahasa tanpa pemeriksaan kelengkapan, literal baru ditangani cabang when others tanpa peringatan apa pun, dan perilaku yang keliru itu baru ditemukan saat program berjalan. Pada Ada, titik yang perlu disesuaikan muncul sebagai error pada waktu kompilasi.

Perulangan for juga menerima rentang yang lebih sempit daripada seluruh tipe. Subtype seperti subtype Arah_Timur is Arah range Timur .. Barat; membatasi nilai yang sah, dan for A in Arah_Timur loop menelusuri tiga literal terakhir saja. Pola ini berguna ketika sebagian literal memang tidak layak diproses pada satu bagian program, tanpa perlu menuliskan rentangnya secara lengkap pada setiap perulangan.

Kesalahan umum#

Tiga kekeliruan berikut sering muncul saat tipe enumeration dipraktikkan.

  • Menganggap nomor posisi sebagai kode representasi internal. Keduanya berbeda dan dapat dipisahkan melalui klausul representasi. Susun representasinya secara eksplisit apabila tipe ini bertukar data dengan perangkat keras.
  • Mengandalkan cabang when others sejak awal. Cabang tersebut menyembunyikan literal baru dari pemeriksaan kelengkapan, sehingga perubahan tipe tidak lagi menandai titik yang perlu disesuaikan. Perinci setiap literal secara eksplisit selama masih dimungkinkan.
  • Memanggil atribut Value terhadap masukan luar tanpa penanganan exception. String yang tidak cocok menghentikan program dengan Constraint_Error. Bungkus konversinya dan tetapkan perilaku untuk masukan yang tidak sah.

Ringkasan#

  • Tipe enumeration memperkenalkan literal sebagai nilai sah tipe baru, dengan nomor posisi menurut urutan deklarasinya.
  • Atribut Pos dan Val mengubah literal menjadi nomor posisi dan sebaliknya, sedangkan Image dan Value menangani teksnya.
  • Pernyataan case wajib mencakup seluruh literal, dan kelengkapan itu diperiksa pada waktu kompilasi.

Referensi#