Submodul

Submodul untuk memisahkan spesifikasi modul dari implementasi prosedurnya.

Daftar isi

Submodul (submodule) adalah unit program yang memisahkan implementasi prosedur modul dari spesifikasinya. Fitur ini diperkenalkan pada standar Fortran 2008. Dengan fitur itu, modul induk cukup mengumumkan antarmuka (interface) prosedurnya, sedangkan tubuh prosedur ditulis di berkas submodul yang terpisah. Topik ini membahas struktur kedua unit tersebut, pernyataan module procedure, cara mengompilasinya dengan gfortran, dan manfaat pemisahan bagi proyek yang prosedurnya besar. Contoh menghitung energi kinetik disusun dalam tiga berkas dan dijalankan utuh pada bagian Kompilasi dan pengujian.

Antarmuka di modul induk#

Modul induk mendeklarasikan prosedur submodul di dalam blok interface dengan kata module di depan definisinya. Deklarasi semacam itu hanya berisi kepala prosedur, yaitu nama, daftar argumen dummy, dan tipe hasil, tanpa tubuh perhitungan. Blok interface ini berperan sebagai kontrak yang lengkap, karena seluruh unit yang menggunakan modul dapat melihat bentuk prosedurnya tanpa perlu melihat implementasinya. Modul berikut mengumumkan satu fungsi energi_kinetik beserta kontrol aksesnya.

fortran bendafisik.f90
module bendafisik
  implicit none
  private
  public :: energi_kinetik

  interface
    module function energi_kinetik(massa, kecepatan) result(energi)
      implicit none
      real, intent(in) :: massa
      real, intent(in) :: kecepatan
      real :: energi
    end function energi_kinetik
  end interface

end module bendafisik

Pemanggil energi_kinetik memperoleh antarmuka eksplisit penuh, termasuk kontrak intent pada kedua argumennya, meskipun tubuh fungsinya berada di tempat lain. Deklarasi di dalam blok interface mengikuti aturan yang sama dengan kepala prosedur biasa, sehingga tipe hasil dapat dinyatakan pada baris module function melalui result atau di dalam tubuh deklarasi. Modul induk semacam ini tetap dapat dikompilasi sendirian meskipun tubuh fungsinya belum ditulis, karena deklarasi di dalam blok interface sudah lengkap bagi compiler. Kode pemanggil juga dapat ditulis dan diperiksa compiler terhadap antarmuka yang sama tanpa menunggu implementasi selesai, meskipun penautan (linking) barulah berhasil setelah implementasinya tersedia. Pengguna modul tidak mengetahui dan tidak perlu mengetahui bahwa implementasinya berada di submodul.

Implementasi di submodul#

Submodul dideklarasikan dengan pernyataan submodule (nama_induk) nama_submodul, dan tubuh prosedur ditulis sebagai module procedure di bagian contains. Nama submodul bebas ditentukan sendiri dan tidak terikat pada nama prosedurnya, sedangkan satu berkas sumber boleh memuat lebih dari satu submodul sekaligus. Nama setelah kata module procedure harus mengikuti nama prosedur yang diumumkan modul induk, dan seluruh daftar argumen dummy beserta tipe hasilnya diambil dari antarmuka tersebut sehingga tidak ditulis ulang. Ketidakcocokan antara implementasi dan antarmuka tertangkap saat kompilasi karena compiler membandingkan keduanya.

fortran bendafisik_impl.f90
submodule (bendafisik) bendafisik_impl
  implicit none
contains

  module procedure energi_kinetik
    ! massa dan kecepatan diwarisi dari antarmuka di modul induk
    energi = 0.5 * massa * kecepatan * kecepatan
  end procedure energi_kinetik

end submodule bendafisik_impl

Submodul mengakses entitas modul induk melalui asosiasi host (host association), yaitu mekanisme yang membuat entitas itu dapat dipakai seolah-olah dideklarasikan di dalam submodul itu sendiri. Submodul juga boleh memuat prosedur lokal tambahan yang tidak diumumkan modul induk, dan prosedur semacam itu tidak terlihat dari luar. Rumus yang diimplementasikan pada submodul di atas adalah energi kinetik klasik,

Ek=12mv2 E_k = \tfrac{1}{2} m v^2

dengan mm menyatakan massa benda dan vv menyatakan kecepatannya.

Kompilasi dan pengujian#

Program uji berikut hanya menyatakan use bendafisik lalu memanggil energi_kinetik, tanpa mengetahui keberadaan submodul. Tidak ada rujukan ke bendafisik_impl di dalamnya, karena nama submodul tidak perlu diketahui pemanggil.

fortran utama.f90
program utama
  use bendafisik
  implicit none
  real :: m, v

  m = 2.0
  v = 3.0
  print '(a, f6.2)', 'Massa           =', m
  print '(a, f6.2)', 'Kecepatan       =', v
  print '(a, f6.2)', 'Energi kinetik  =', energi_kinetik(m, v)

end program utama
bash
# mengompilasi modul induk, submodul, lalu program utamanya
gfortran bendafisik.f90 bendafisik_impl.f90 utama.f90 -o benda
# menjalankan program
./benda
text Keluaran
Massa           =  2.00
Kecepatan       =  3.00
Energi kinetik  =  9.00

Urutan berkas pada perintah kompilasi penting. Modul induk dikompilasi lebih dahulu karena menghasilkan berkas antarmuka, yaitu bendafisik.mod dan pada gfortran juga bendafisik.smod, yang dibaca oleh submodul dan program utama. Kesalahan urutan ini dapat direproduksi dengan menghapus kedua berkas antarmuka tersebut, lalu mengompilasi submodul lebih dahulu.

bash
# menghapus berkas antarmuka hasil kompilasi sebelumnya
rm bendafisik.mod bendafisik.smod
# mencoba mengompilasi submodul lebih dahulu sebelum modul induknya
gfortran bendafisik_impl.f90 utama.f90 -o benda
text Keluaran
f951: Fatal Error: Module file ‘bendafisik.smod’ has not been generated, either because the module does not contain a MODULE PROCEDURE or there is an error in the module.
compilation terminated.
utama.f90:2:7:

    2 |   use bendafisik
      |       1
Fatal Error: Cannot open module file ‘bendafisik.mod’ for reading at (1): No such file or directory
compilation terminated.

Pesan errornya menyebut kedua berkas antarmuka yang belum ada, yaitu bendafisik.smod untuk submodul dan bendafisik.mod untuk pengguna modul. Kedua pesan berasal dari satu penyebab yang sama, yaitu modul induk yang belum dikompilasi. Kompilasi hanya berhasil kembali setelah modul induk dikompilasi lebih dahulu, sehingga urutan yang benar adalah modul induk, submodul, kemudian program utama.

Manfaat pemisahan spesifikasi dan implementasi#

Pemisahan ini memberi tiga keuntungan pada proyek yang besar. Pertama, kompilasi menjadi lebih hemat karena perubahan pada tubuh prosedur hanya menuntut kompilasi ulang submodulnya, sedangkan unit yang menggunakan modul induk tidak tersentuh karena antarmukanya tidak berubah. Pola ini memutus rantai kompilasi ulang yang biasa dialami modul besar yang prosedurnya ditulis langsung di dalam modulnya. Kedua, pembaca modul hanya melihat kontrak, sedangkan detail algoritma berada di berkas lain, sehingga spesifikasi dapat ditinjau dan didokumentasikan tanpa terganggu ratusan baris implementasi.

Struktur hierarkis juga didukung, karena satu submodul dapat menjadi induk bagi submodul lain yang menyediakan implementasi untuk prosedur yang diumumkannya. Entitas yang dideklarasikan lokal di dalam satu submodul tidak terlihat oleh submodul lain yang setingkat dengannya, sehingga detail antar-implementasi tetap tersembunyi satu sama lain. Dengan pola ini, satu prosedur besar dapat dipecah ke beberapa submodul keturunan tanpa membuka detailnya kepada pengguna modul.

Keuntungan ketiga terasa pada kerja tim dan pustaka (library). Penyedia pustaka dapat memperbarui implementasi tanpa mengubah satu baris pun pada kode penggunanya, sebab kontrak pada modul induk tetap sama. Dua versi implementasi, misalnya versi sederhana dan versi yang dioptimasi, dapat ditempatkan pada dua submodul berbeda dan dipilih pada saat penautan, tanpa menyentuh spesifikasi maupun pemanggilnya.

Ringkasan#

  • Modul induk mengumumkan prosedur di dalam blok interface dengan kata module, sedangkan submodul menyediakan tubuhnya melalui module procedure.
  • Argumen dummy dan tipe hasil diwarisi dari antarmuka tanpa ditulis ulang, dan submodul mengakses entitas induk melalui asosiasi host.
  • Pemisahan ini memutus rantai kompilasi ulang serta menyembunyikan detail implementasi, dengan urutan kompilasi modul induk lebih dahulu.

Referensi#