Inisialisasi objek tipe turunan ditangani oleh tiga sarana yang saling melengkapi, yaitu nilai bawaan pada komponen, constructor struktur bawaan bahasa, dan fungsi pabrik yang dibuat sendiri. Topik ini membahas ketiganya beserta aturan alokasi komponen allocatable pada saat constructor dijalankan. Satu modul sensor suhu disertakan dan dijalankan, sehingga perilaku setiap bentuk inisialisasi terlihat dari keluaran aslinya.
Nilai bawaan pada komponen#
Nilai bawaan (default initialization) dinyatakan langsung pada deklarasi komponen dengan tanda sama dengan, misalnya real :: suhu = 0.0. Nilai itu harus berupa ekspresi konstanta yang dapat dihitung pada saat kompilasi, dan berlaku setiap kali sebuah objek tipe tersebut dibuat tanpa nilai eksplisit untuk komponen itu, baik saat variabel dideklarasikan maupun saat objek dibangun oleh constructor. Dengan cara ini komponen yang sering bernilai sama, seperti penghitung yang mulai dari nol, tidak perlu diisi ulang di setiap tempat variabel dibuat.
Komponen yang diberi nilai bawaan pada deklarasi tipe tidak memerlukan penugasan manual setelahnya, sedangkan komponen tanpa nilai bawaan berstatus tidak terdefinisi apabila tidak pernah diisi. Perbedaan ini penting bagi komponen allocatable, karena komponen semacam itu tidak dapat diberi nilai bawaan dan status awalnya selalu tidak teralokasi. Kondisi alokasinya diperiksa dengan fungsi intrinsik allocated() sebelum komponen dibaca atau ditulis.
Constructor struktur bawaan bahasa#
Constructor struktur menghasilkan satu nilai lengkap bertipe turunan dengan menuliskan nama tipe diikuti tanda kurung, misalnya sensor(). Apabila tanda kurung dibiarkan kosong, seluruh komponen memperoleh nilai bawaannya, sedangkan komponen yang diberi nilai dinyatakan mengikuti urutan deklarasi atau dengan menyebut namanya secara eksplisit seperti sensor(id="sensor-ruang", suhu=27.4). Penulisan dengan nama membuat urutan argumen bebas dan maksud setiap nilai terbaca langsung, sehingga disarankan untuk tipe dengan banyak komponen.
Komponen yang tidak disebutkan pada constructor memperoleh nilai bawaannya bila tersedia, dan menjadi tidak terdefinisi bila tidak tersedia. Untuk komponen allocatable, aturannya berbeda, yaitu komponen itu dialokasikan otomatis dengan bentuk sesuai nilai yang diberikan pada constructor, dan tetap tidak teralokasi apabila dilewatkan. Penugasan hasil constructor ke objek yang sudah ada menggantikan seluruh isi lama, termasuk membebaskan alokasi komponen allocatable yang lama sebelum mengisi yang baru.
Constructor tambahan melalui fungsi#
Constructor bawaan bahasa tidak dapat menambahkan logika apa pun, misalnya pemeriksaan masukan atau penyiapan data turunan, sehingga pola yang lazim adalah membuat fungsi pabrik yang mengembalikan objek bertipe tersebut. Fungsi buat_sensor pada modul contoh menerima nama, suhu, dan deret bacaan, lalu mengembalikan objek sensor yang sudah lengkap dengan komponen bacaan teralokasi. Pemanggil c = buat_sensor("sensor-atap", 31.2, [28.5, 29.0, 28.7]) memperoleh objek yang siap pakai tanpa pernah menyentuh komponennya satu per satu.
Pola pabrik ini menjadi wajib ketika ada aturan yang harus dipatuhi setiap kali objek dibuat, misalnya menolak deret kosong atau menghitung nilai rata-rata awal. Aturan yang ditulis di dalam satu fungsi pabrik dipatuhi seluruh program, sedangkan aturan yang hanya ditulis sebagai komentar mudah terlewat di tempat lain. Fortran juga menyediakan mekanisme overload untuk constructor, yaitu antarmuka generik yang bernama sama dengan tipenya, sehingga fungsi pabrik semacam ini boleh dipanggil dengan nama tipe itu sendiri, tetapi contoh pada modul ini sengaja memberi nama sendiri agar perannya sebagai pabrik terlihat jelas.
Program uji inisialisasi#
Program berikut memuat modul data_sensor yang mendeklarasikan tipe sensor dengan tiga nilai bawaan dan satu komponen allocatable, serta fungsi pabrik buat_sensor. Unit program utama kemudian membangun tiga objek dengan tiga cara berbeda untuk membandingkan hasilnya.
module data_sensor
implicit none
type :: sensor
character(len=16) :: id = "sensor-00"
real :: suhu = 0.0
logical :: aktif = .true.
real, allocatable :: bacaan(:)
end type sensor
contains
function buat_sensor(nama_id, suhu, deret) result(s)
character(len=*), intent(in) :: nama_id
real, intent(in) :: suhu
real, intent(in) :: deret(:)
type(sensor) :: s
s = sensor(id=nama_id, suhu=suhu, bacaan=deret)
end function buat_sensor
end module data_sensor
program uji_constructor
use data_sensor
implicit none
type(sensor) :: a, b, c
a = sensor()
b = sensor(id="sensor-ruang", suhu=27.4)
c = buat_sensor("sensor-atap", 31.2, [28.5, 29.0, 28.7])
print '(1X, A16, 1X, F6.1, 1X, L1)', a%id, a%suhu, a%aktif
print '(1X, A16, 1X, F6.1, 1X, L1)', b%id, b%suhu, b%aktif
print '(1X, A16, 1X, F6.1, 1X, L1, 1X, 3F6.1)', c%id, c%suhu, c%aktif, c%bacaan
print '(1X, A, L1, 1X, A, L1)', "bacaan a terisi:", allocated(a%bacaan), &
"bacaan c terisi:", allocated(c%bacaan)
end program uji_constructor# mengompilasi program dari direktori topik
gfortran constructor.f90 -o constructor
# menjalankan program hasil kompilasi
./constructor sensor-00 0.0 T
sensor-ruang 27.4 T
sensor-atap 31.2 T 28.5 29.0 28.7
bacaan a terisi:F bacaan c terisi:TKeluaran memperlihatkan ketiga jalur inisialisasi secara berurutan. Objek a yang dibangun dengan sensor() seluruhnya mengikuti nilai bawaan, mulai dari id sensor-00, suhu nol, hingga status aktif. Objek b hanya mengganti id dan suhu melalui argumen bernama, sedangkan aktif tetap memperoleh nilai bawaannya. Objek c berasal dari fungsi pabrik dan satu-satunya yang menyimpan deret bacaan, yang dibuktikan oleh baris terakhir, yaitu bacaan milik a tidak teralokasi sedangkan milik c teralokasi.
Kesalahan umum#
Kesalahan pertama adalah membaca komponen allocatable tanpa memeriksa status alokasinya. Pada objek a di atas, pernyataan yang membaca a%bacaan akan gagal pada saat program berjalan karena komponen itu belum dialokasi, dan pesan errornya baru muncul saat eksekusi, bukan saat kompilasi. Kebiasaan yang aman adalah membungkus aksesnya dengan allocated(), sebagaimana dilakukan baris pencetak terakhir pada program contoh.
Kesalahan kedua adalah mengira setiap komponen otomatis bernilai nol atau kosong. Tanpa nilai bawaan pada deklarasi tipe, komponen yang tidak diisi bernilai tak terdefinisi, dan membacanya menghasilkan perilaku yang tidak dapat diandalkan. Kesalahan ketiga adalah menghilangkan satu argumen pada constructor padahal komponen itu tidak punya nilai bawaan, karena constructor tetap diterima compiler dan masalahnya baru terlihat saat program berjalan. Pendekatan yang aman adalah memberi nilai bawaan pada setiap komponen yang punya nilai awal yang wajar.
Ringkasan#
- Nilai bawaan dinyatakan pada deklarasi komponen dengan ekspresi konstanta, dan berlaku setiap kali objek dibuat tanpa nilai eksplisit untuk komponen tersebut.
- Constructor struktur menerima argumen berurutan atau bernama, komponen yang dilewatkan mengikuti nilai bawaannya, dan komponen allocatable dialokasikan hanya bila diberi nilai.
- Fungsi pabrik menggantikan overload constructor untuk membungkus logika pembuatan, dan status komponen allocatable diperiksa dengan
allocated()sebelum diakses.
Referensi#
- Learn: tutorial resmi Fortran — fortran-lang — Kumpulan tutorial resmi komunitas Fortran yang menjadi rujukan fitur bahasa pada jalur ini.
- The GNU Fortran Compiler — GNU Project — Manual gfortran, compiler yang digunakan untuk menjalankan seluruh contoh kode pada jalur ini.