1 poin oleh GN⁺ 2025-11-08 | Belum ada komentar. | Bagikan ke WhatsApp
  • Kompiler Zig yang menyediakan kompilasi kode C dan cross-compilation secara bawaan adalah bahasa paling menakjubkan yang pernah ditemui penulis dalam 45 tahun pengalamannya
  • Dengan fitur unik seperti eksekusi saat waktu kompilasi, variabel dengan ukuran bit arbitrer, dan lingkungan blok test, Zig melampaui sekadar pengganti C/C++ dan menawarkan cara pemrograman yang benar-benar baru
  • Dengan sintaks yang ringkas dan jelas seperti deklarasi variabel melalui inferensi tipe, struct anonim, dan label break, Zig dapat dipelajari dengan cepat
  • Dengan pengujian modul secara independen melalui blok test dan fungsi bawaan @breakpoint Zig mendukung debugging kode teroptimasi
  • Dengan dukungan pemrograman tingkat rendah melalui bit field dan operasi bit, Zig mencapai efisiensi dan ketangguhan sekaligus, sambil mengintegrasikan keunggulan bahasa interpreter ke dalam bahasa terkompilasi

Pendahuluan

  • Dalam 45 tahun pengalaman, tidak ada bahasa yang semenarik Zig
    • Zig bukan sekadar bahasa baru, melainkan alat yang secara mendasar mengubah cara pemrograman
  • Melihatnya hanya sebagai pengganti C atau C++ adalah peremehan besar
  • Tujuan tulisan ini adalah memperkenalkan fitur-fitur Zig yang sederhana namun menarik, dan membantu programmer agar bisa cepat mulai menggunakannya
  • Masih ada lebih banyak fitur yang memengaruhi tingkat penerimaan Zig di industri

Kompiler Zig

  • Menyediakan kompilasi kode C dan cross-compilation secara default tanpa konfigurasi tambahan, yang memberi dampak besar di industri
  • Instalasi dilakukan dengan mengunduh kompiler sesuai prosesor/OS dari halaman unduhan Zinglang, lalu mengekstraknya dan menyalinnya ke direktori yang diinginkan
    • Di Windows 10, file zip x86_64 dapat disalin ke "Program Files", lalu nama direktori root diubah menjadi "zig-windows-x86_64" agar tidak perlu mengubah variabel lingkungan Path saat versi diperbarui
    • Setelah menambahkan jalur direktori root ke variabel lingkungan Path, kompiler dapat digunakan dalam mode CLI
  • Untuk membangun program "Hello World!", disarankan merujuk ke bagian "Getting Started" di situs resmi

Konsep dan perintah utama

Deklarasi variabel

  • Deklarasi variabel terdiri dari bagian pertama berupa aksesibilitas (pub atau dihilangkan), var/const, dan nama variabel, bagian kedua berupa deklarasi tipe, serta bagian ketiga berupa inisialisasi
    • Hanya bagian pertama dan ketiga yang wajib, dan tipe dapat diinferensikan dari nilai inisialisasi
    • Contoh: var sum : usize = 0;
  • Variabel yang dideklarasikan tanpa pub hanya dapat diakses di dalam modul (mirip variabel static di C)
  • Deklarasi variabel pub tidak dianjurkan, dan fungsi pub sebaiknya diminimalkan untuk menurunkan coupling dan meningkatkan cohesion

Struct, struct anonim, dan blok test

  • Literal struct anonim yang dibungkus oleh .{ dan } digunakan untuk menginisialisasi elemen struct lain atau membuat struct baru dengan elemen yang sudah diinisialisasi
  • .{ } adalah literal struct anonim kosong
  • Bentuk struct { } adalah deklarasi struct
  • Blok test memungkinkan kompilasi dan eksekusi pengujian tanpa file executable

Bit field

  • Bit field dideklarasikan sebagai field bertipe ukuran tertentu di dalam packed struct
  • Pointer dapat menunjuk ke bit field tertentu

Loop for

  • Sintaks Zig lebih jelas daripada C, tetapi menggunakan interval terbuka [0..9) alih-alih [0..8]
  • Deklarasi tipe, inisialisasi, pengujian, dan kenaikan variabel loop i ditangani secara otomatis

Array

  • [_] mendefinisikan array dengan ukuran yang tidak diketahui, diikuti oleh tipe elemen dan inisialisasi
    • Contoh: var grid = [_]u8{0} ** 81; menginisialisasi 81 elemen u8 dengan 0
    • Ukuran array diinferensikan dari argumen pengulangan inisialisasi
  • Dalam lingkungan test, elemen array dapat dijumlahkan sambil diiterasi
  • Variabel yang dideklarasikan di antara | pada loop for otomatis diasumsikan bertipe sama dengan elemen array
  • usize adalah bilangan bulat tak bertanda alami platform (u64 di 64-bit, u32 di 32-bit)

Pointer multi-item

  • Agar pointer array dapat menggunakan operasi aritmetika pointer, pointer itu harus secara eksplisit dideklarasikan sebagai pointer multi-item seperti [*]const i32
  • Meski array bersifat const, pointer tetap dapat dideklarasikan sebagai var

Dereferensi pointer

  • Pointer yang diberi alamat posisi array individual tidak dapat diperbarui dengan aritmetika pointer
  • Dereferensi pointer menggunakan ptr.*

Label break

  • Berbagai tugas seperti inisialisasi array dapat dilakukan pada waktu kompilasi
  • Label break menambahkan : setelah nama blok, lalu mengembalikan nilai dari blok dengan break
    • Contoh: break :init m;
  • 0.. adalah rentang tak terbatas yang dimulai dari 0
  • Dalam loop for, variabel diinisialisasi dan dinaikkan secara otomatis, dan loop berhenti setelah posisi terakhir array diproses
  • Array tidak harus diinisialisasi secara eksplisit dengan undefined

Fungsi di Zig

  • Fungsi dideklarasikan dengan fn dan secara default bersifat static (hanya dipakai di dalam file)
    • Jika dideklarasikan dengan pub fn, fungsi dapat di-import dari file lain
  • Fungsi dapat di-"inlined"
  • Pointer fungsi menempatkan const di depan dan prototipe fungsi di belakang

Pemrograman berorientasi objek di Zig

  • Struct dapat memiliki fungsi
  • Dalam contoh stack, maksimal 81 elemen bertipe StkNode dapat disimpan
  • Operator ++ dan -- tidak ada di Zig, dan sebagai gantinya digunakan += serta -=
  • Pointer stack adalah bilangan bulat yang digunakan sebagai indeks array stk
  • Pointer self tidak diteruskan secara eksplisit sebagai parameter, melainkan diasumsikan secara tidak langsung sebagai pointer ke instance stack tempat fungsi dipanggil
    • Saat dipanggil seperti stack.pop(), self adalah pointer ke stack (mirip this di Java/C++)
  • Fungsi init() adalah konstruktor stack
  • Fungsi pop dan push di-"inlined"

Membangun dan menjalankan program Zig

Membangun executable

  • Untuk membuat executable, dibutuhkan fungsi main yang menandai entry point program
  • Program sederhana dapat menempatkan fungsi main di file yang sama
  • Untuk debugging modul secara independen, fungsi main dapat ditambahkan di akhir file lalu dikomentari kembali setelah debugging selesai
  • Perintah kompilasi: zig build-exe -O ReleaseFast program.zig

Menjalankan blok test modul

  • Ini adalah salah satu fitur terbaik Zig, digunakan untuk testing dan prototyping
  • Blok test dimulai dengan test "message" { dan diakhiri dengan }
    • "message" adalah string yang ditampilkan saat test dijalankan
  • Blok test dijalankan secara independen dari executable, dan executable final tidak menjalankan test
  • Perintah test: zig test module.zig
  • Blok test di example.zig menguji fungsi set dan print; set menerima string desimal sebagai parameter, dan print mencetak header "Input Grid" lalu menampilkan grid

Output di Zig

  • Pernyataan std.debug.print memanggil fungsi print di debug.zig dari pustaka standar Zig std
  • Parameter pertama adalah string format, dan parameter kedua adalah struct anonim yang berisi daftar variabel untuk ditampilkan
  • Jika tidak ada format, struct tersebut kosong
  • Secara default ditampilkan ke stderr
  • Tidak seperti printf di C, Zig dapat memproses string literal dan daftar variabel pada waktu kompilasi

Debugging executable

  • Penggunaan debugger tidak mudah kecuali dengan IDE yang memiliki debugger terintegrasi (Eclipse, IntelliJ IDEA) atau kit pengembangan terintegrasi (w64devkit)
  • Integrasi simbol membuat kode membengkak dan mengharuskan kompilasi mode Debug, sehingga menghasilkan kode eksekusi yang jauh kurang efisien
  • Zig menyediakan solusi praktis untuk menghindari masalah ini

Fungsi bawaan @breakpoint

  • Dengan menyisipkan @breakpoint(); ke dalam source code, program akan berhenti di titik tersebut saat dijalankan di debugger
  • Ini adalah fitur berguna untuk melakukan debugging kode Zig teroptimasi tanpa simbol
  • Jika std.debug.print digunakan tepat sebelum @breakpoint(); untuk mencetak variabel yang ingin dilacak, nilai variabel saat itu dapat diperiksa
  • Dalam contoh debug_example.zig, kode untuk mencetak grid dan variabel di dalam fungsi set, serta @breakpoint();, disisipkan
  • Perintah build: zig build-exe debug_example.zig
  • Setelah memanggil debug_example.exe dengan debugger seperti gdb, jalankan program dengan perintah r
  • Gunakan perintah c untuk melanjutkan sambil melacak isi grid dan variabel
  • Jika terus menekan Enter untuk melanjutkan, dapat dipastikan bahwa nilai-nilai grid sesuai dengan blok test di example.zig

Pemrograman tingkat rendah di Zig

Representasi matriks

  • Digit desimal disimpan di matriks sebagai bilangan bulat standar u8
  • Grid input berbentuk string, tetapi karakter ASCII secara internal dikonversi menjadi bilangan bulat u8
  • Penyimpanan angka disusun secara linear per baris ke dalam array grid yang memiliki 81 posisi: var grid = [_]u8{0} ** 81;
  • Untuk memverifikasi kebenaran grid, elemen perlu diakses per baris dan kolom
  • Array berisi 9 pointer dibuat, dan masing-masing pointer menunjuk ke awal tiap baris
  • Label break digunakan untuk mengembalikan nilai dari blok kode: break :fill9x9 m; menginisialisasi matrix dengan m
  • Notasi akses elemen: element = matrix[i][j]

Merepresentasikan digit desimal sebagai bit

  • Konsep inti adalah mengganti digit desimal bulat i dengan bilangan bulat code
    • i ∈ [1,9] → code = 2ⁱ⁻¹
    • i = 0 → code = 0
  • Posisi satu-satunya bit 1 yang disetel dalam code adalah i-1 (saat i berada di antara 1 dan 9); jika tidak, semua bit bernilai 0
  • Disediakan tabel nilai code untuk tiap digit (1→1, 2→2, 3→4, ..., 9→256)

Menghitung code di Zig

  • Saat c tidak sama dengan 0, nilai code dihitung dengan operator shift kiri: code = @as(u9,1) << (c-1);
  • Di Zig, konstanta harus memiliki ukuran yang sesuai agar operasi dapat dikompilasi dan hasilnya dapat ditugaskan ke variabel
  • code dideklarasikan sebagai tipe u9 (karena nilai maksimum 256 memerlukan minimal 9 bit)
  • Zig dapat memiliki variabel dengan ukuran bit arbitrer
  • Fungsi bawaan @as digunakan untuk melakukan cast konstanta 1 ke tipe u9

Representasi grid dengan bit field

Grid bit field per baris

  • Array lines mencerminkan seluruh grid dengan merepresentasikan tiap baris sebagai bilangan bulat 9-bit: var lines = [_]u9{0} ** 9;
  • Saat array diakses dengan baris i, keberadaan angka tertentu di baris itu dapat diperiksa dengan operasi bit AND (&): lines[i] & code
  • Jika hasil operasi adalah 0, angka tersebut belum ada di baris i; jika tidak, berarti ada duplikasi

Grid bit field per kolom

  • Array columns mencerminkan seluruh grid dengan merepresentasikan tiap kolom sebagai bilangan bulat 9-bit: var columns = [_]u9{0} ** 9;
  • Saat array diakses dengan kolom j, keberadaan angka tertentu di kolom itu dapat diperiksa dengan operasi bit AND: columns[j] & code
  • Jika hasil operasi adalah 0, angka tersebut belum ada di kolom j; jika tidak, berarti ada duplikasi

Aturan Sudoku

  • Saat memasukkan angka baru ke grid Sudoku kosong, angka itu tidak boleh sudah ada di seluruh baris, kolom, dan sel yang memuat elemen baru tersebut
  • Sel adalah masing-masing dari 9 grid 3x3 yang dipisahkan garis tebal
  • Setiap elemen tertentu dalam grid 9x9 memiliki baris, kolom, dan sel unik yang memuatnya
  • Pada grid contoh, sel pertama berisi 3, 5, 6, 8, 9, sedangkan 1, 2, 4, dan 7 tidak ada
  • Array lines dan columns menangani pemeriksaan duplikasi untuk baris dan kolom
  • Diperlukan array baru untuk memeriksa duplikasi pada sel

Grid bit field per sel

  • Array cells mencerminkan seluruh grid dengan merepresentasikan tiap sel sebagai bilangan bulat 9-bit: var cells = [_]u9{0} ** 9;
  • Akses ke cells akan lebih mudah jika diperlakukan sebagai matriks 3x3
  • Array cell diisi dengan cara yang mirip seperti pada matriks 9x9
  • Dari baris dan kolom elemen pada grid 9x9 asli, perlu ditentukan baris dan kolom pada matriks cell
  • Karena pembagian bilangan bulat sangat lambat, array cindx = [_]usize{ 0,0,0, 1,1,1, 2,2,2 }; digunakan untuk memberikan hasil pembagian
  • Saat matriks diakses dengan baris i dan kolom j dari elemen grid 9x9, keberadaan angka tertentu di sel elemen itu dapat diperiksa dengan operasi bit AND: cell[cindx[i]][cindx[j]] & code
  • Jika hasil operasi adalah 0, angka tersebut belum ada di sel; jika tidak, berarti ada duplikasi

Menguji duplikasi elemen

  • Dengan menggabungkan semua elemen sebelumnya pada baris, kolom, dan sel yang sama menggunakan bit OR (|), lalu melakukan bit AND dengan code milik elemen tersebut, verifikasi duplikasi elemen selesai dilakukan
if (((lines[i]|columns[j]|cell[cindx[i]][cindx[j]])&code) != 0) {  
    unreachable;  
}  
  • Jika hasilnya 0, elemen tersebut belum ada di baris, kolom, maupun sel
  • Jika hasilnya bukan 0, program berhenti dengan menjalankan perintah unreachable
  • Ini adalah cara paling sederhana di Zig untuk secara eksplisit menunjukkan runtime error
  • Kode sebenarnya juga mencetak detail lokasi terjadinya error
  • Contoh: jika 0 tepat setelah 8 pertama dalam string input diganti menjadi 5, maka terjadi error karena di baris 3 kolom 1 sudah ada angka 5

Memperbarui struktur data

  • Di fungsi set, loop for ganda berinteraksi per baris untuk menyalin tiap elemen baru dari string input s ke grid
    • Variabel k menjaga indeks karakter input baru dalam string s
  • Karakter dikonversi ke u4 (variabel c) dengan mengurangkan '0'
  • Jika elemen baru yang akan dimasukkan ke grid bukan 0 (c != 0), code yang dihitung dengan operasi shift kiri disalin ke tiap grid cerminan
    • Lalu dilakukan bit OR (|=) dengan grid cerminan terkait:
lines[i] |= code;  
columns[j] |= code;  
cell[cindx[i]][cindx[j]] |= code;  
  • Tidak perlu menguji secara eksplisit apakah nilai c berada di antara 1 dan 9 — karena overflow akan terjadi saat operasi shift dijalankan
  • Contoh: jika 0 tepat setelah 8 pertama pada string input diganti menjadi :, maka terjadi runtime error
  • Mengganti 0 yang sama dengan / juga akan menimbulkan runtime error serupa
  • Program hanya bekerja saat nilainya berada di rentang 1 sampai 9, yaitu ketika grid input hanya berisi digit desimal
  • Banyak grid Sudoku di web merepresentasikan 0 sebagai ., sehingga fungsi set memiliki baris if (s[k] == '.') c = 0;
  • Ini memudahkan untuk melewati operasi shift karena nilai c adalah 0

Prototyping dan ketangguhan

  • Error yang dipaksakan pada dua bagian di atas mendemonstrasikan fitur penting Zig
  • Salah satunya adalah ketangguhan Zig — pada operasi shift, perilaku yang salah tidak diizinkan dan akan ditangkap saat runtime
  • Meski semua upaya tampak diarahkan ke efisiensi, ini adalah contoh khas ketika performa dipertukarkan dengan ketangguhan
  • Di C, jika operasi shift kehilangan bit, itu menjadi masalah programmer, dan hal ini diterjemahkan menjadi performa lebih baik dari instruksi assembler tertentu
  • Fitur lainnya adalah kemungkinan menggunakan blok test untuk prototyping
  • Kemungkinan penerapannya tak terhitung banyaknya, dan penerapan yang ditunjukkan di sini hanyalah debugging situasi tertentu saat error terjadi
  • Fitur-fitur ini saja sudah memberikan kemampuan menakjubkan yang sangat jarang ditemukan dalam bahasa pemrograman, terutama bahasa pemrograman terkompilasi

Kesimpulan

  • Zig terdiri dari tiga elemen kunci: kompatibilitas dengan C, cross-compilation, dan instalasi yang sederhana
  • Karakteristik ini menunjukkan potensinya untuk menjadi standar baru bahasa pemrograman sistem
  • Banyak keunggulan yang sebelumnya hanya ditemukan pada bahasa interpreter secara bertahap berpindah ke bahasa terkompilasi untuk memberikan performa yang lebih baik
  • Zig sangat menonjol kemiripannya dengan bahasa interpreter melalui konsep eksekusi saat waktu kompilasi
  • Hal ini membuat Zig terasa sangat berbeda dan kuat, sekaligus juga lebih sulit dipahami

Belum ada komentar.

Belum ada komentar.