Modul dan package

Menata struktur import dan membangun paket precompiled dengan mojoc.

Daftar isi

Mojo menata kode yang dapat digunakan ulang melalui dua unit, yaitu modul dan package. Modul adalah satu berkas .mojo yang memuat fungsi, struct, atau konstanta, sedangkan package adalah direktori berisi beberapa modul yang disatukan oleh berkas __init__.mojo. Topik ini membahas cara membuat keduanya, cara menulis import yang benar dari sisi pemakai, dan cara mengubah package menjadi paket precompiled berupa berkas .mojoc dengan perintah mojo precompile. Seluruh contoh berada pada satu direktori dan dijalankan dengan mojo run, sehingga hubungan antara berkas sumber dan nama yang diimpor dapat ditelusuri sampai ke keluarannya.

Modul sebagai unit import terkecil#

Modul dalam Mojo adalah berkas .mojo tunggal yang isinya dapat diimpor oleh berkas lain tanpa konfigurasi tambahan. Berkas geometri.mojo berikut memuat dua fungsi biasa, dan nama modulnya adalah geometri, sesuai nama berkasnya.

mojo geometri.mojo
def luas_persegi(sisi: Int) -> Int:
    return sisi * sisi

def keliling_persegi(sisi: Int) -> Int:
    return 4 * sisi

Di sisi pemakai, fungsi yang dibutuhkan diimpor melalui pernyataan from ... import, lalu dipanggil seperti fungsi lokal. Berkas pakai-geometri.mojo berada di direktori yang sama dengan geometri.mojo, sehingga pencarian modulnya langsung berhasil.

mojo pakai-geometri.mojo
from geometri import luas_persegi, keliling_persegi

def main():
    print(luas_persegi(5))
    print(keliling_persegi(5))
bash
# modul geometri dicari pada direktori yang sama
mojo run pakai-geometri.mojo
text Keluaran
25
20

Keluaran 25 adalah luas persegi bersisi lima, sedangkan 20 adalah kelilingnya. Tidak ada langkah registrasi atau berkas konfigurasi yang diperlukan, karena penamaan modul mengikuti nama berkas secara langsung. Konvensi ini berlaku untuk semua program Mojo, termasuk program yang nantinya memakai package.

Satu modul sebaiknya menampung satu tanggung jawab, dan contoh pada topik ini mengikuti kebiasaan tersebut. Modul geometri hanya menyimpan fungsi bangun datar, sedangkan fungsi ringkasan angka berada pada package terpisah yang dibahas di bawah. Pemisahan semacam ini membuat pencarian fungsi cepat karena nama modul langsung menggambarkan isinya, dan perubahan satu tanggung jawab tidak menyentuh berkas tanggung jawab lain.

Package: direktori dengan init.mojo#

Package mengelompokkan beberapa modul ke dalam satu direktori yang wajib memuat berkas __init__.mojo, sehingga direktori itu dapat diimpor sebagai satu nama. Struktur direktori contoh pada topik ini terlihat seperti berikut.

text Struktur direktori contoh
├── geometri.mojo
├── pakai-geometri.mojo
├── pakai-statistik.mojo
├── pakai-artefak.mojo
└── statistik/
    ├── __init__.mojo
    └── ringkas.mojo

Direktori statistik adalah sebuah package yang memuat satu modul bernama ringkas. Isi modul tersebut adalah dua fungsi statistik sederhana.

mojo statistik/ringkas.mojo
def rata_rata(nilai: List[Float64]) -> Float64:
    var total = 0.0
    for x in nilai:
        total += x
    return total / Float64(len(nilai))

def maksimum(nilai: List[Float64]) -> Float64:
    var terbesar = nilai[0]
    for x in nilai:
        if x > terbesar:
            terbesar = x
    return terbesar

Berkas __init__.mojo menentukan nama yang tampak di sisi import. Barisnya memindahkan rata_rata dan maksimum dari modul ringkas ke ruang nama package, sebuah teknik yang disebut re-export.

mojo statistik/__init__.mojo
from .ringkas import rata_rata, maksimum

Dengan re-export tersebut, pemakai mengimpor langsung dari nama package tanpa perlu tahu modul di dalamnya.

mojo pakai-statistik.mojo
from statistik import rata_rata, maksimum

def main():
    var nilai: List[Float64] = [7.5, 8.0, 6.5, 9.0]
    print(rata_rata(nilai))
    print(maksimum(nilai))
bash
# package statistik diimpor lewat nama hasil re-export
mojo run pakai-statistik.mojo
text Keluaran
7.75
9.0

Import langsung ke modul di dalam package juga sah, seperti bentuk from statistik.ringkas import rata_rata berikut. Bentuk ini berguna apabila dua modul dalam satu package memuat nama yang sama dan pemakai ingin memilih sumbernya secara eksplisit.

mojo Contoh: import langsung ke modul dalam package
# tidak-dijalankan
from statistik.ringkas import rata_rata

Paket precompiled dengan mojoc#

Perintah mojo precompile mengubah package menjadi paket precompiled berupa satu berkas .mojoc, sehingga import tidak lagi membaca ulang seluruh berkas sumber di dalamnya. Nama berkas pada opsi -o menentukan nama modul yang diimpor pemakai, dan nama tersebut boleh berbeda dari nama direktori sumbernya. Artefaknya diletakkan pada direktori proyek dan langsung menjadi bagian pencarian import.

Manfaat utamanya muncul saat package berisi banyak berkas, karena bantuan resminya menyebut paket precompiled lebih cepat dipakai oleh build dibandingkan membangunnya dari sumber. Konsekuensinya, setiap perubahan isi package menuntut precompile ulang agar artefaknya ikut berubah. Untuk package sekecil statistik di sini, manfaatnya lebih berupa kebiasaan kerja yang rapi, sedangkan keuntungan performanya baru terasa pada package yang terus membesar.

bash
# precompile package statistik menjadi artefak bernama laporan
mojo precompile statistik -o laporan.mojoc

Perintah di atas tidak mencetak apa pun ketika berhasil, dan berkas laporan.mojoc muncul di direktori proyek. Karena artefak dinamai laporan, berkas pemakainya mengimpor dari nama tersebut.

mojo pakai-artefak.mojo
from laporan import rata_rata

def main():
    var nilai: List[Float64] = [7.5, 8.0, 6.5, 9.0]
    print(rata_rata(nilai))
bash
# import mengikuti nama artefak pada opsi -o
mojo run pakai-artefak.mojo
text Keluaran
7.75

Bantuan resmi mojo precompile mencatat dua batasan yang patut diingat. Artefak .mojoc terikat pada versi compiler yang menghasilkannya, sehingga memuat artefak dengan versi compiler yang berbeda akan error, dan format ini bukan format distribusi untuk pengguna akhir. Selain itu, subperintah lama mojo package kini berstatus deprecated, yaitu masih berjalan tetapi menyuruh penggunanya beralih ke mojo precompile.

Kesalahan umum#

Tiga kesalahan berikut paling sering muncul saat menata package pada Mojo. Masing-masing disertai penyebab dan perbaikannya.

  • Import ditulis sebelum artefak dibuat, atau nama yang diimpor tidak cocok dengan opsi -o. Compiler menolak berkasnya dengan pesan error: unable to locate module 'laporan' pada baris importnya. Perbaikannya adalah menjalankan mojo precompile statistik -o laporan.mojoc terlebih dahulu, atau menyamakan nama pada opsi -o dengan nama yang diimpor.
  • Subperintah mojo package dipakai karena kebiasaan lama. Perintah ini masih menghasilkan berkas, tetapi setiap pemanggilannya mencetak peringatan 'package' is deprecated; use 'precompile' instead. Perbaikannya adalah mengganti seluruh pemanggilan dengan mojo precompile.
  • Berkas .mojoc dipindahkan ke lingkungan dengan versi compiler yang berbeda. Artefak hanya dijamin dimuat dengan benar oleh versi compiler yang sama, sehingga perbaikannya adalah menjalankan mojo precompile ulang di lingkungan target.

Ringkasan#

  • Modul adalah berkas .mojo tunggal, dan importnya ditulis from geometri import luas_persegi sesuai nama berkasnya.
  • Package adalah direktori dengan __init__.mojo, dan from .ringkas import rata_rata di dalamnya membuat fungsi dapat diimpor langsung dari nama package.
  • mojo precompile statistik -o laporan.mojoc menghasilkan paket precompiled yang diimpor sesuai nama pada opsi -o, dengan syarat versi compiler sama.

Referensi#