Modul dan import

Semantik import, export, from, dan include dalam mengorganisasi kode Nim.

Daftar isi

Nim mengelompokkan kode ke dalam modul, yaitu satu berkas sumber yang membentuk unit kompilasi tersendiri dengan ruang nama dan batas keterlihatannya sendiri. Topik ini membahas empat pernyataan yang mengatur perpindahan simbol antar berkas, yaitu import yang memuat seluruh isi modul, from ... import yang memuat sebagian, export yang meneruskan simbol milik modul lain, serta include yang menyisipkan berkas secara tekstual. Seluruh contoh memakai satu paket kecil konversi suhu sehingga efek setiap pernyataan terlihat pada berkas yang sama-sama sederhana.

Batas keterlihatan simbol pada modul#

Secara bawaan, seluruh simbol di dalam satu modul bersifat privat, artinya tidak terlihat dari berkas lain. Sebuah proc, tipe, atau konstanta menjadi publik apabila namanya diakhiri tanda bintang, sehingga tanda bintanglah yang menjadi kontrak antarmuka sebuah modul. Program pertama menyimpan dua konversi suhu yang diekspor dan satu proc validasi yang sengaja dibiarkan privat sebagai pembatasan internal, misalnya pemeriksaan yang masih berubah-ubah dan belum layak dijanjikan kepada pemakai modul.

nim matematika_dasar.nim
# modul matematika_dasar.nim: konversi suhu

proc celciusKeFahrenheit*(c: float): float =
  ## Mengonversi suhu Celcius ke Fahrenheit.
  result = c * 9.0 / 5.0 + 32.0

proc celciusKeReaumur*(c: float): float =
  ## Mengonversi suhu Celcius ke skala Reaumur.
  result = c * 4.0 / 5.0

proc validasi(c: float): bool =
  ## Proc tanpa tanda bintang, sehingga bersifat privat.
  c > -273.15

when isMainModule:
  echo celciusKeFahrenheit(25.0)
bash
# menjalankan modul secara langsung untuk menguji konversinya
nim c --hints:off -r matematika_dasar.nim
text Keluaran
77.0

Blok when isMainModule membuat pengujian kecil itu hanya berjalan ketika berkas dikompilasi sebagai program utama, dan tidak berjalan ketika berkas tersebut dimuat oleh modul lain. Pola ini menjaga berkas tetap dapat diuji sendiri tanpa menambahkan keluaran samping pada program yang mengimpornya.

Memuat simbol dengan import dan from#

Pernyataan import matematika_dasar memuat seluruh simbol publik modul ke dalam ruang nama berkas pengimpor, sehingga celciusKeFahrenheit dapat dipanggil tanpa awalan. Kompilator menemukan berkas modul dari jalur pencarian yang mencakup direktori program utama, dan urutan pencarian tersebut dapat diperluas dengan opsi --path apabila proyek menyusun berkasnya dalam beberapa direktori.

nim konversi_suhu.nim
# konversi_suhu.nim: menggunakan simbol dari modul matematika_dasar

import matematika_dasar

for c in [0.0, 25.0, 100.0]:
  echo "celcius: ", c, " -> fahrenheit: ", celciusKeFahrenheit(c)
bash
# menjalankan program yang mengimpor modul konversi suhu
nim c --hints:off -r konversi_suhu.nim
text Keluaran
celcius: 0.0 -> fahrenheit: 32.0
celcius: 25.0 -> fahrenheit: 77.0
celcius: 100.0 -> fahrenheit: 212.0

Selain bentuk tanpa kualifikasi, simbol yang sudah dimuat juga tetap dapat dipanggil dengan nama modulnya sebagai awalan, misalnya matematika_dasar.celciusKeFahrenheit(25.0), dan bentuk berawalan ini sah untuk semua simbol publik modul tanpa memandang pernyataan impornya. Kebiasaan memakai awalan pada berkas yang memakai dua modul serupa membuat sumber setiap pemanggilan tetap terbaca. Bila kebalikannya yang diinginkan, yaitu seluruh simbol wajib ditulis berawalan, bentuk from matematika_dasar import nil memuat modul tanpa memasukkan satu pun simbolnya ke ruang nama.

Bentuk from ... import memuat hanya simbol yang disebut, sehingga sumber setiap pengenal terbaca langsung pada baris pernyataannya. Cara ini mengurangi risiko tabrakan nama pada berkas yang mengimpor banyak modul, karena simbol yang tidak disebut tidak ikut masuk ruang nama.

nim sapaan_upper.nim
# sapaan_upper.nim: hanya memuat simbol yang dibutuhkan

from strutils import toUpperAscii

echo toUpperAscii("pustaka nim")
bash
# menjalankan program dengan from dan import sebagian
nim c --hints:off -r sapaan_upper.nim
text Keluaran
PUSTAKA NIM

Meneruskan simbol dengan export#

Paket yang tumbuh sering tersusun atas beberapa modul, dan mengimpor modulnya satu per satu menjadi merepotkan bagi pemakainya. Pernyataan export menjawab kebutuhan itu dengan meneruskan seluruh simbol publik satu modul melalui modul lain, sehingga modul penerus berperan sebagai fasad. Berbeda dari import yang hanya memakai simbol untuk dirinya sendiri, export membuat simbol tersebut dapat diimpor kembali oleh pihak ketiga.

nim paket_matematika.nim
# paket_matematika.nim: fasad yang menyusun ulang modul matematika_dasar

import matematika_dasar

export matematika_dasar

when isMainModule:
  echo celciusKeReaumur(50.0)
nim hitung_paket.nim
# hitung_paket.nim: mengambil simbol melalui fasad paket_matematika

import paket_matematika

echo celciusKeReaumur(100.0)
bash
# menjalankan program yang mengambil simbol melalui fasad
nim c --hints:off -r hitung_paket.nim
text Keluaran
80.0

Program pengguna tidak pernah menyebut matematika_dasar, karena celciusKeReaumur sampai kepadanya melalui fasad. Pernyataan export juga dapat menyaring isinya, misalnya export matematika_dasar except validasi meneruskan segalanya kecuali yang disebut setelah kata kunci tersebut, dan beberapa export pada satu fasad menyusun permukaan paket dari banyak modul sekaligus. Kombinasi import lalu export inilah yang membedakan berkas fasad dari berkas biasa, karena berkas itu sendiri hampir tidak memuat kode.

Apabila suatu saat konversi dipecah ke beberapa modul, hanya fasad yang perlu disunting, dan seluruh pemakai paket tetap menulis import paket_matematika tanpa perubahan. Peta berikut merangkum arah perpindahan simbol pada seluruh berkas contoh topik ini.

konversi_suhu.nimmatematika_dasar.nimimportsapaan_upper.nimstrutilspustaka standarfrom ... import ...tampilkan_konfigurasi.nimberkas indukkonfigurasi.niminclude (sisipan teks)
Peta relasi antar berkas pada contoh modul, dari import penuh, from import sebagian, sampai include tekstual

Menyisipkan berkas dengan include#

Pernyataan include tidak mengenal batas modul, melainkan menyalin isi berkas lain secara tekstual ke posisi pernyataannya, seolah-olah kedua berkas digabungkan menjadi satu. Karena tidak ada ruang nama baru yang terbentuk, seluruh simbol berkas yang disisipkan langsung terlihat tanpa tanda bintang sekalipun. Mekanisme ini pas untuk potongan konfigurasi yang dipakai oleh beberapa program sekolah kode sekaligus, dan tidak digantikan oleh import karena keduanya membedakan hal yang berbeda, yaitu batas unit kompilasi.

nim konfigurasi.nim
# konfigurasi.nim: konstanta yang akan disisipkan dengan include

const namaAplikasi = "Penghitung Kata"
const versiAplikasi = "1.0"
nim tampilkan_konfigurasi.nim
# tampilkan_konfigurasi.nim: menyisipkan isi konfigurasi.nim secara tekstual

include konfigurasi

echo namaAplikasi, " versi ", versiAplikasi
bash
# menjalankan program yang menyisipkan berkas konfigurasi
nim c --hints:off -r tampilkan_konfigurasi.nim
text Keluaran
Penghitung Kata versi 1.0

Konstanta namaAplikasi tidak diberi tanda bintang, tetapi tetap terlihat karena include tidak membentuk batas modul sama sekali. Konsekuensinya juga serius, yaitu nama yang sama pada dua berkas yang keduanya disisipkan akan bertabrakan, sehingga include sebaiknya dipakai hemat dan hanya untuk berkas yang memang dirancang untuk disisipkan.

Kesalahan umum#

  • Memanggil proc privat dari modul lain. Pengenal tanpa tanda bintang tidak keluar dari modulnya, dan upaya pemanggilan ditolak saat kompilasi dengan pesan Error: undeclared identifier: 'validasi' pada posisi pemanggilan. Simbol yang memang dimaksudkan untuk pemakai luar wajib diekspor dengan tanda bintang.
  • Mengimpor dua modul yang mengekspor nama sama lalu memanggilnya tanpa kualifikasi. Kompilator menolak dengan Error: ambiguous call yang menyebut kedua kandidat beserta berkasnya, dan pemecahannya memakai bentuk mod_a.label(25.0) atau menyaring simbol dengan from mod_a import label.
  • Menganggap include sebagai padanan ringan import. include menggandakan isi berkas ke setiap titik penyisipannya, sehingga konstanta yang sama dideklarasikan berulang kali dan justru memunculkan error definisi ganda apabila berkas yang sama disisipkan dua kali pada satu berkas.

Ringkasan#

  • Simbol Nim bersifat privat secara bawaan, dan tanda bintang pada nama adalah satu-satunya cara mengekspornya ke pemakai modul lain.
  • import memuat seluruh simbol publik modul, from ... import memuat yang disebut saja, sedangkan export meneruskan simbol modul lain sehingga modul penerus menjadi fasad paket.
  • include menyisipkan berkas secara tekstual tanpa ruang nama baru, cocok untuk konstanta bersama, dan perbedaannya dengan import wajib dipahami sebelum dipilih.

Referensi#