Topik ini membahas record sebagai cara memberi nama pada bidang tuple: deklarasi dengan -record, pembuatan dan pembaruan dengan sintaks pagar, nilai bawaan bidang, serta pembacaan record di shell lewat rr/1. Setelah membaca, data bertanda yang sebelumnya ditulis {buku, Judul, Tahun} memperoleh bentuk yang lebih aman dan terbaca.
Mengapa record dibutuhkan#
Tuple bertanda seperti {buku, "Judul", 2020} memaksa setiap pemakainya mengingat posisi bidang. Mengambil tahun berarti memanggil element(3, B) tanpa penjelasan apa pun di kodenya, dan menukar urutan bidang diam-diam merusak semua pemakai. Record menyelesaikan masalah ini dengan memberi nama pada setiap posisi: akses ditulis B#buku.tahun, dan compiler menerjemahkannya kembali ke indeks tuple. Record bukan tipe baru, melainkan gula sintaksis (syntactic sugar), yaitu notasi yang lebih nyaman dibaca di atas tuple biasa, sehingga ukurannya tetap dan pencocokan pola tetap bekerja seperti tuple.
Deklarasi dan pembuatan#
Record dideklarasikan dengan atribut -record yang menampung nama record dan bidang-bidangnya, lengkap dengan nilai bawaan bila ada. Modul berikut mendefinisikan record buku dengan tiga bidang, satu di antaranya bernilai bawaan 2000:
-module(perpustakaan).
-export([contoh/0, label/1]).
-record(buku, {judul, pengarang, tahun = 2000}).
contoh() -> #buku{judul = "Dasar Erlang", pengarang = "Ali"}.
label(B) -> io_lib:format("~s (~p)", [B#buku.judul, B#buku.tahun]).Pembuatan memakai sintaks #buku{...} dengan bidang yang ingin diisi. Bidang yang tidak disebutkan mengambil nilai bawaannya, dan bila tidak ada nilai bawaan, isinya menjadi atom undefined. Sesi berikut memperlihatkan pemuatan definisi lewat rr/1, akses bidang, dan pembaruan:
Erlang/OTP 29 [erts-17.1.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1] [jit:ns]
Eshell V17.1.1 (press Ctrl+G to abort, type help(). for help)
1> c(perpustakaan).
{ok,perpustakaan}
2> rr(perpustakaan).
[buku]
3> R = perpustakaan:contoh().
#buku{judul = "Dasar Erlang",pengarang = "Ali",tahun = 2000}
4> R#buku.judul.
"Dasar Erlang"
5> R#buku.tahun.
2000
6> B2 = R#buku{tahun = 2020}.
#buku{judul = "Dasar Erlang",pengarang = "Ali",tahun = 2020}Fungsi rr(perpustakaan) membaca definisi record dari modul yang baru dikompilasi sehingga shell dapat membuat dan mencetaknya, dan pengembaliannya adalah daftar nama record yang dimuat. Pembaruan R#buku{tahun = 2020} tidak mengubah R, melainkan menghasilkan record baru, konsisten dengan sifat data yang tidak berubah. Bidang judul dan pengarang tetap terbawa karena pembaruan hanya menyentuh bidang yang disebutkan.
Record di balik layar#
Karena record hanyalah tuple, ukurannya dapat diperiksa langsung. Record buku memiliki tiga bidang, dan tuple di baliknya menyimpan nama record sebagai elemen pertama:
7> tuple_size(R).
4
8> #buku{judul = "Buku Shell"}.
#buku{judul = "Buku Shell",pengarang = undefined,
tahun = 2000}tuple_size/1 mengembalikan 4, yaitu satu elemen nama plus tiga bidang. Pencetakan #buku{judul = "Buku Shell"} menegaskan dua aturan nilai bawaan: pengarang yang tidak punya nilai bawaan terisi undefined, sedangkan tahun yang punya terisi 2000. Pengetahuan ini praktis saat mendebug data yang datang dari antarmuka eksternal, karena pesan error dan pencocokan pola tetap memakai bentuk tuple mentahnya.
Definisi record di berkas header#
Record yang dipakai lebih dari satu modul lazim disimpan di berkas header .hrl dan disertakan dengan atribut -include. Bentuknya persis sama dengan deklarasi di modul, dan compiler menyisipkannya di tempat atribut itu berada:
%% buku.hrl
-record(buku, {judul, pengarang, tahun = 2000}).-module(perpustakaan).
-include("buku.hrl").Modul contoh topik ini mendeklarasikan record langsung di badan modul karena hanya dipakai di satu tempat, sedangkan konvensi .hrl menjadi wajib begitu lebih dari satu modul memakai record yang sama. Setiap modul yang menyertakan berkas yang sama memperoleh tata letak tuple yang identik, dan perubahan bidang otomatis mengikuti setiap pemakai pada kompilasi berikutnya.
Pencocokan pola pada record#
Record mengikuti semua aturan pencocokan pola, dengan pola yang juga ditulis dalam bentuk record. Pola #buku{judul = J} menerima record apa pun bertipe buku dan mengikat bidang judulnya:
9> #buku{judul = J} = R.
#buku{judul = "Dasar Erlang",pengarang = "Ali",tahun = 2000}
10> J.
"Dasar Erlang"Bidang yang tidak disebut pada pola diperlakukan sebagai variabel tanpa nama, sehingga pola di atas cocok dengan record buku apa pun tanpa memandang pengarang dan tahun. Kombinasi pola record dan guard pada klausa fungsi menjadi cara baku menyaring data terstruktur, dan bidang yang wajib diisi dapat dituntut langsung di pola tanpa pemeriksaan element/2 manual.
Fungsi pemeriksa is_record/2 menegaskan kedudukan record sebagai tuple bertanda. Pembanding kesetaraan juga melihat record sebagai tuple biasa:
4> is_record(R, buku).
true
5> R == {buku, "Dasar Erlang", "Ali", 2000}.
truePerbandingan terakhir bernilai true karena record memang sama persis dengan tuple empat elemen itu. Manfaatnya ganda: fungsi lama yang bekerja pada tuple tetap menerima record, dan data bertanda dari luar sistem dapat dicocokkan dengan record yang benar bila tata letaknya identik. Sisi baliknya, dua record dengan nama sama di dua modul yang tata letak bidangnya berbeda tidak dapat dipertukarkan, meski pencetakannya terlihat mirip.
Kesalahan umum#
- Menggunakan record di shell tanpa memuat definisinya. Pembuatan
#buku{...}gagal dengan pesan record buku undefined sebelumrr/1dijalankan. Muat dulu denganrr(Modul)setiap kali shell baru dibuka. - Menganggap record sebagai tipe baru. Fungsi seperti
element/2dantuple_size/1tetap bekerja padanya, dan pencocokan tuple mentah tetap sah. Gunakan sintaks record untuk kejelasan, bukan karena keamanan tambahan. - Menukar urutan bidang pada pembandingan tuple mentah. Record dua modul dengan nama sama tetapi urutan bidang berbeda menghasilkan tuple yang berbeda, sehingga perbandingan diam-diam bernilai
falsetanpa pesan apa pun. Satukan definisi di berkas.hrlagar tata letaknya tunggal.
Ringkasan#
- Record adalah gula sintaksis di atas tuple: deklarasi -record, pembuatan #buku{…}, akses #buku.bidang, dan pembaruan yang menghasilkan record baru.
- Bidang tanpa nilai bawaan terisi undefined, sedangkan bidang dengan nilai bawaan terisi nilainya saat pembuatan.
- rr(Modul) memuat definisi record ke shell, dan tuple di balik record menyimpan nama record sebagai elemen pertama sehingga tuple_size satu lebih besar dari jumlah bidang.
- Pencocokan pola record mengikat bidang yang disebut dan mengabaikan sisanya.
Referensi#
- Erlang Reference Manual: Records — Ericsson — Dokumentasi resmi deklarasi, pembuatan, dan pembaruan record.
- Erlang Reference Manual: Macros — Ericsson — Dokumentasi resmi atribut, termasuk makro yang sering dipakai bersama record.
- Learn You Some Erlang for Great Good! — Fred Hebert — Bab record beserta kebiasaan pemakaiannya.