Nama dan klausa use

Nama terkualifikasi sebagai pilihan utama dan disiplin penggunaan klausa use.

Daftar isi

Nama yang diekspor oleh sebuah package dapat digunakan dengan dua gaya, yaitu nama terkualifikasi (qualified name) yang menuliskan nama package sebagai awalan, atau nama langsung yang dimungkinkan oleh klausa use (use clause). Topik ini membahas kedua gaya tersebut, alasan nama terkualifikasi menjadi pilihan baku, dan disiplin penggunaan klausa use. Contoh pada topik ini menggunakan package konversi satuan yang ringkas, serta dua package kecil yang sengaja dipertemukan untuk memunculkan benturan nama.

Nama terkualifikasi sebagai pilihan baku#

Nama terkualifikasi berbentuk Nama_Package.Entitas, sehingga asal setiap nama terbaca langsung pada tempat penggunaannya. Spesifikasi berikut hanya memuat dua konstanta konversi tanpa subprogram, sehingga package ini tidak memerlukan badan dan spesifikasinya berdiri sendiri.

ada konversi_satuan.ads
package Konversi_Satuan is

   Inci_Per_Cm : constant := 0.393700787;
   Pon_Per_Kg  : constant := 2.20462262;

end Konversi_Satuan;

Program utama berikut menggunakan kedua konstanta tersebut dengan menuliskan nama package asal secara lengkap, termasuk pemanggilan Ada.Text_IO yang juga ditulis terkualifikasi.

ada uji_terkualifikasi.adb
with Ada.Text_IO;
with Ada.Float_Text_IO;
with Konversi_Satuan;

--  Semua nama package ditulis lengkap: gaya nama terkualifikasi.
procedure Uji_Terkualifikasi is
   Tinggi_Cm : constant Float := 180.0;
   Berat_Kg  : constant Float := 70.0;
begin
   Ada.Text_IO.Put ("180.0 cm = ");
   Ada.Float_Text_IO.Put
     (Tinggi_Cm * Konversi_Satuan.Inci_Per_Cm, Fore => 1, Aft => 2, Exp => 0);
   Ada.Text_IO.Put_Line (" inci");

   Ada.Text_IO.Put ("70.0 kg  = ");
   Ada.Float_Text_IO.Put
     (Berat_Kg * Konversi_Satuan.Pon_Per_Kg, Fore => 1, Aft => 2, Exp => 0);
   Ada.Text_IO.Put_Line (" pon");
end Uji_Terkualifikasi;
bash
# kompilasi program dengan nama terkualifikasi
gnatmake uji_terkualifikasi.adb
text Keluaran
gcc -c uji_terkualifikasi.adb
gcc -c konversi_satuan.ads
gnatbind -x uji_terkualifikasi.ali
gnatlink uji_terkualifikasi.ali
bash
# jalankan program pertama
./uji_terkualifikasi
text Keluaran
180.0 cm = 70.87 inci
70.0 kg  = 154.32 pon

Keluaran kompilasi memperlihatkan bahwa spesifikasi konversi_satuan.ads dikompilasi sebagai unit tersendiri, karena package tanpa subprogram tidak membutuhkan badan. Pada baris program, setiap nama konversi membawa awalannya, sehingga pembaca kode langsung mengetahui bahwa Inci_Per_Cm berasal dari Konversi_Satuan. Gaya inilah yang disarankan untuk program dengan banyak package.

Manfaat nama terkualifikasi paling terlihat pada penelusuran kode. Pencarian teks terhadap Konversi_Satuan.Inci_Per_Cm menemukan setiap tempat penggunaan konstanta itu, sedangkan pencarian terhadap nama langsung tidak dapat membedakan asalnya. Peninjauan kode (code review) juga terbantu karena penilai tidak perlu membuka berkas lain untuk mengetahui sumber sebuah nama. Biayanya hanya berupa penulisan nama yang lebih panjang.

Klausa use dan visibilitas langsung#

Klausa use menjadikan seluruh nama yang diekspor oleh sebuah package terlihat langsung, sehingga awalan nama package tidak perlu lagi dituliskan. Klausa ini diletakkan setelah klausa with untuk package yang sama, dan efeknya berlaku pada lingkup tempat klausa itu ditulis.

ada uji_klausa_use.adb
with Ada.Text_IO;
with Ada.Float_Text_IO;
with Konversi_Satuan;
use  Konversi_Satuan;

--  Klausa use membuat nama konstanta dapat ditulis langsung.
procedure Uji_Klausa_Use is
   Tinggi_Cm : constant Float := 180.0;
begin
   Ada.Text_IO.Put ("180.0 cm = ");
   Ada.Float_Text_IO.Put
     (Tinggi_Cm * Inci_Per_Cm, Fore => 1, Aft => 2, Exp => 0);
   Ada.Text_IO.Put_Line (" inci");
end Uji_Klausa_Use;
bash
# kompilasi program dengan klausa use
gnatmake uji_klausa_use.adb
text Keluaran
gcc -c uji_klausa_use.adb
gnatbind -x uji_klausa_use.ali
gnatlink uji_klausa_use.ali
bash
# jalankan program kedua
./uji_klausa_use
text Keluaran
180.0 cm = 70.87 inci

Hasilnya identik dengan versi terkualifikasi, tetapi gaya ini menuntut kehati-hatian tambahan karena asal setiap nama harus diingat dari klausa use di bagian atas berkas. Disiplin yang lazim adalah menahan diri, yaitu tetap menggunakan nama terkualifikasi secara default dan menambahkan klausa use hanya apabila package itu dominan pada berkas tersebut, misalnya Ada.Text_IO pada program yang banyak menampilkan teks. Klausa use juga tidak menggantikan klausa with, karena visibilitas langsung hanya berlaku pada package yang sudah disebutkan oleh klausa with.

Klausa use tidak harus diletakkan di bagian atas berkas. Deklarasi use dapat ditulis pada bagian deklaratif sebuah subprogram, sehingga visibilitas langsungnya hanya berlaku di dalam subprogram itu. Teknik ini membatasi lingkup yang dipengaruhi nama tanpa awalan, dan pembaca tetap mendapat kejelasan pada sisa berkas. Bentuk terbatas semacam ini merupakan kompromi yang lazim antara keringkasan dan kejelasan.

Disiplin klausa use dapat diringkas menjadi tiga pertimbangan. Pertama, gunakan nama terkualifikasi secara default dan jadikan klausa use sebagai pengecualian yang disengaja. Kedua, batasi lingkup klausa use seminimal mungkin, misalnya di dalam satu subprogram alih-alih satu berkas. Ketiga, hindari klausa use untuk package yang mengekspor nama-nama umum seperti Batas atau Panjang, karena kemungkinan benturannya tinggi. Ketiganya menjaga program tetap mudah dibaca ketika jumlah package bertambah.

Kesalahan umum#

Kesalahan pertama adalah menuliskan klausa use tanpa klausa with untuk package yang sama. Kompilator menolak program tersebut karena package yang tidak disebutkan oleh klausa with tidak terlihat sama sekali, sehingga klausa use tidak memiliki nama yang dapat dibuat terlihat. Perbaikannya sederhana, yaitu menambahkan klausa with di atas klausa use. Kesalahan kedua lebih tersembunyi karena program tampak wajar, yaitu menumpuk klausa use dari beberapa package yang mengekspor nama sama.

ada modul_a.ads
package Modul_A is

   Batas : constant := 100;

end Modul_A;
ada modul_b.ads
package Modul_B is

   Batas : constant := 250;

end Modul_B;
ada uji_ambigu.adb
with Ada.Text_IO;
with Modul_A;
use  Modul_A;
with Modul_B;
use  Modul_B;

--  Berkas ini sengaja salah: dua klausa use memunculkan nama yang sama.
procedure Uji_Ambigu is
begin
   Ada.Text_IO.Put_Line (Integer'Image (Batas));
end Uji_Ambigu;
bash
# kompilasi program yang memunculkan ambiguitas
gnatmake uji_ambigu.adb
text Keluaran
gcc -c uji_ambigu.adb
uji_ambigu.adb:10:41: error: "Batas" is not visible
uji_ambigu.adb:10:41: error: multiple use clauses cause hiding
uji_ambigu.adb:10:41: error: hidden declaration at modul_b.ads:3
uji_ambigu.adb:10:41: error: hidden declaration at modul_a.ads:3
gnatmake: "uji_ambigu.adb" compilation error

Pesan error menyatakan Batas tidak terlihat karena dua klausa use saling menyembunyikan deklarasi yang bentrok, dan kedua sumbernya ditunjukkan satu per satu. Bahasa memilih perilaku ini daripada menebak salah satu nilai. Apabila kompilator memilih salah satu deklarasi secara diam-diam, perubahan urutan klausa use akan mengubah arti program tanpa pesan apa pun. Dengan menyatakan nama itu tidak terlihat, bahasa memaksa penulis menyampaikan maksudnya secara eksplisit. Perbaikannya adalah menuliskan nama terkualifikasi pada penggunaannya, misalnya Modul_A.Batas, sehingga maksud program menjadi tegas dan kompilasi berhasil.

Benturan seperti contoh di atas sering kali merupakan sinyal desain, yaitu nama yang diekspor terlalu umum untuk ditulis tanpa awalan. Mengganti nama pada sumber merupakan perbaikan yang lebih permanen daripada menambahkan awalan pada setiap penggunaan, misalnya memberi nama konstanta yang memuat konteks package asalnya. Kedua perbaikan itu saling melengkapi, yaitu nama terkualifikasi menyelesaikan kompilasi saat ini, sedangkan penamaan yang lebih spesifik mencegah persoalan yang sama terulang.

Ringkasan#

  • Nama terkualifikasi seperti Konversi_Satuan.Inci_Per_Cm adalah gaya baku yang menuliskan asal setiap nama pada tempat penggunaannya.
  • Klausa use memberikan visibilitas langsung atas nama sebuah package yang sudah disebut oleh klausa with, dan penggunaannya lebih aman pada lingkup kecil untuk package yang dominan.
  • Penumpukan klausa use dari package yang mengekspor nama sama membuat nama itu tidak terlihat, dan perbaikannya adalah kembali ke nama terkualifikasi.

Referensi#