DEV Community

Cover image for Variabel, Imutabilitas, dan Garbage Collection
Muzhawir Amri
Muzhawir Amri

Posted on • Edited on • Originally published at muzhawir.com

Variabel, Imutabilitas, dan Garbage Collection

Daftar Isi


Di Elixir, data bersifat tetap, setelah dibuat nilainya tidak bisa diubah. Jika kita menulis ulang sebuah variabel, Elixir tidak mengganti nilai lama, tetapi membuat nilai baru dan mengaitkan nama yang sama ke nilai tersebut. Cara kerja ini disebut immutability. Dalam pelajaran ini kita akan mempelajari bagaimana immutability diterapkan melalui binding, cara menamai variabel dengan benar, konsep rebinding, serta bagaimana garbage collector di BEAM mengelola memori agar program tetap efisien dan berjalan lancar.

Binding - Membuat Variabel

Membuat variable di Elixir sekilas tampak mirip dengan bahasa pemrograman imperatif seperti Ruby atau Python, tetapi cara Elixir memperlakukan nilai berbeda secara mendasar.

Di Bahasa Imperatif - Kotak yang Dapat Diisi Ulang

Dalam bahasa seperti Ruby, variable bersifat mutable (dapat diubah):

irb(main):001:0> monthly_salary = 5_000_000
=> 5000000

irb(main):002:0> monthly_salary = 6_000_000
=> 6000000
Enter fullscreen mode Exit fullscreen mode

Kita dapat membayangkan variable monthly_salary sebagai kotak bernama.

Pertama, kotak itu diisi dengan nilai 5_000_000. Ketika nilainya diperbarui menjadi 6_000_000, isi kotak yang sama diganti. Kotaknya tetap sama, tetapi isinya berubah.

Sifat ini disebut mutable, artinya data dapat dimodifikasi setelah dibuat.

Secara teknis, variable dalam bahasa imperatif menunjuk ke lokasi memori tetap, dan nilai di lokasi tersebut dapat diganti kapan saja. Perubahan ini dianggap sebagai “pembaruan nilai”.

Di Elixir - Kotak Tersegel

Sekilas, sintaks pembuatan variable di Elixir terlihat serupa:

iex> monthly_salary = 5_000_000
5000000
Enter fullscreen mode Exit fullscreen mode

Namun konsep di baliknya sangat berbeda.

Kita dapat membayangkan nilai 5_000_000 ditempatkan di dalam kotak tersegel, lalu diberi label monthly_salary. Karena kotaknya tersegel, isinya tidak dapat diubah. Sifat ini disebut immutable.

Jika kita menulis ulang monthly_salary dengan nilai baru:

iex> monthly_salary = 6_000_000
6000000
Enter fullscreen mode Exit fullscreen mode

Elixir tidak membuka kotak lama dan mengganti isinya. Ia membuat kotak baru yang berisi 6_000_000, lalu memindahkan label nama monthly_salary ke kotak baru tersebut. Kotak lama tetap ada hingga sistem garbage collector menghapusnya ketika sudah tidak digunakan.

Binding di Elixir bukan hubungan antara nama dan lokasi memori yang bisa dimodifikasi, melainkan antara nama dan nilai. Nama hanyalah label yang menunjuk pada suatu nilai, bukan wadah yang menyimpannya.

Kita dapat mengamati perilaku ini langsung di IEx:

iex> monthly_salary = 5_000_000
5000000

iex> monthly_salary
5000000

iex> monthly_salary * 12
60000000
Enter fullscreen mode Exit fullscreen mode

Nilai aslinya tetap sama. Ketika kita melakukan binding baru untuk monthly_salary, Elixir tidak mengubah nilai lama, melainkan membentuk asosiasi baru antara nama dan nilai yang baru.

Tipe Data Ditentukan Otomatis

Elixir adalah bahasa dinamis, artinya tipe data ditentukan otomatis berdasarkan nilai yang diberikan:

name = "Alice"   # string
age = 30         # integer
height = 1.72    # float
Enter fullscreen mode Exit fullscreen mode

Kita tidak perlu menentukan tipe data secara eksplisit karena runtime Elixir mengenali tipe setiap nilai secara otomatis. Pendekatan ini membuat kode lebih ringkas dan fleksibel tanpa mengorbankan kejelasan logika.

Penamaan Variabel

Penamaan variable di Elixir mengikuti aturan sederhana namun penting untuk menjaga kejelasan kode. Nama harus diawali dengan huruf kecil (a-z) atau garis bawah (_). Setelah karakter pertama, kita dapat menambahkan huruf, angka (0-9), atau garis bawah tambahan. Garis bawah biasanya digunakan untuk memisahkan kata dalam nama variable sebagai pengganti spasi.

# Contoh nama variable valid
valid_variable_name
also_valid_1

validButNotRecommended
Enter fullscreen mode Exit fullscreen mode

Huruf kapital di awal tidak diperbolehkan untuk nama variable:

# Contoh tidak valid
VariableName  # error: huruf kapital di awal
Enter fullscreen mode Exit fullscreen mode

Dalam Elixir, huruf kapital di awal nama digunakan secara khusus untuk module (misalnya String, Map, List).

Perbedaan gaya ini memudahkan kita membedakan apakah suatu nama merujuk pada module atau variable hanya dengan melihatnya sekilas.

Akhiran Tanda Tanya dan Tanda Seru

Elixir mengizinkan penggunaan tanda tanya (?) dan tanda seru (!) di akhir nama variable.

Kedua tanda ini tidak memengaruhi perilaku kode secara teknis, tetapi merupakan konvensi idiomatik yang membantu pembaca memahami maksud kode dengan cepat.

  • Tanda tanya (?) menunjukkan bahwa nilai bersifat logis atau menghasilkan boolean. Nama seperti valid?, empty?, atau active? biasanya menandakan pertanyaan yang dapat dijawab "ya" atau "tidak".
  • Tanda seru (!) menandai nilai atau operasi penting, tegas, atau berpotensi berisiko. Dalam konteks variable, tanda ini sering digunakan untuk menandakan bahwa nilai tersebut sudah diverifikasi atau dijamin ada. Contohnya, important_data! dapat berarti “nilai ini pasti tersedia dan aman digunakan”.

Contoh penggunaannya:

user_valid? = true
important_data! = "Nilai ini dijamin tersedia"
Enter fullscreen mode Exit fullscreen mode

Meskipun konvensi ini tidak wajib, penamaan yang konsisten membuat kode jauh lebih mudah dibaca dan dipahami, baik oleh diri sendiri maupun orang lain di masa depan.

Rebinding - Memperbarui Nilai Variabel

Semua data di Elixir bersifat immutable, artinya nilai yang sudah dibuat tidak dapat diubah. Jadi, ketika kita menulis ulang sebuah variable seperti ini:

monthly_salary = 6_000_000
Enter fullscreen mode Exit fullscreen mode

yang terjadi bukan penggantian isi nilai lama, melainkan pembuatan nilai baru dan pengaitan ulang nama monthly_salary ke nilai tersebut.

Proses ini disebut rebinding.

Secara konseptual, rebinding adalah cara Elixir mempertahankan fleksibilitas tanpa melanggar prinsip immutability.

Kita tetap dapat "memperbarui" variable, tetapi yang berubah hanyalah hubungan antara nama dan nilai, bukan isi nilai itu sendiri. Nilai lama tetap ada di memori hingga garbage collector menghapusnya secara otomatis.

Contoh rebinding di IEx:

iex> monthly_salary = 5_000_000  
5000000

iex> monthly_salary  
5000000

iex> monthly_salary = 5_123_000  
5123000

iex> monthly_salary  
5123000
Enter fullscreen mode Exit fullscreen mode

Penjelasannya:

  • ❶ Nama monthly_salary pertama kali di-bind ke nilai 5_000_000.
  • ❷ Saat diperiksa, nama tersebut mengacu pada nilai 5000000.
  • ❸ Nama monthly_salary kemudian di-rebind ke nilai baru 5_123_000.
  • ❹ Kini monthly_salary mengacu pada nilai baru 5123000.

Setiap kali kita melakukan rebinding, BEAM (mesin virtual yang menjalankan Elixir) tidak mengubah nilai lama di memori. Ia membuat alokasi baru untuk nilai baru dan memperbarui referensi nama ke sana. Jika tidak ada referensi yang tersisa ke nilai lama, BEAM akan menghapusnya melalui mekanisme garbage collection.

Manajemen Memori di Elixir

Elixir menggunakan garbage collector (GC) yang terintegrasi di dalam runtime BEAM untuk mengelola memori secara otomatis.

Tugas utama GC adalah mendeteksi data yang sudah tidak lagi digunakan dan membebaskan ruang memori yang ditempati data tersebut.

Kita dapat melihat peran GC ketika melakukan rebinding:

iex> monthly_salary = 5_000_000
5000000

iex> monthly_salary = 6_000_000
6000000
Enter fullscreen mode Exit fullscreen mode

Setelah baris kedua dijalankan, nama monthly_salary tidak lagi mengacu pada nilai 5_000_000, melainkan pada nilai baru 6_000_000. Karena tidak ada referensi lain yang menunjuk ke nilai lama, BEAM menandainya sebagai data yang tidak dibutuhkan lagi. Garbage collector kemudian membebaskan memori yang digunakan nilai tersebut agar dapat dipakai ulang oleh sistem.

Yang membuat BEAM istimewa adalah cara kerjanya yang berbasis proses.
Setiap proses Elixir memiliki ruang memori sendiri (heap) dan garbage collector-nya sendiri. Dengan demikian, setiap proses menjalankan manajemen memorinya secara independen. Ketika satu proses melakukan garbage collection, proses lain tetap berjalan tanpa terhenti, sehingga sistem secara keseluruhan tetap responsif.

Pendekatan ini memberikan dua keuntungan utama:

  • Efisiensi dan prediktabilitas: setiap proses hanya mengelola memorinya sendiri, sehingga siklus garbage collection berlangsung cepat dan terukur.
  • Stabilitas sistem: masalah pada satu proses tidak memengaruhi proses lain, membuat sistem tetap berjalan bahkan di bawah beban tinggi.

Semua ini berlangsung otomatis di belakang layar, kita tidak perlu mengatur alokasi atau pembebasan memori secara manual seperti pada bahasa C atau C++.

Elixir dan BEAM menangani seluruh siklus hidup data secara mandiri, memungkinkan kita fokus pada logika program tanpa khawatir terhadap kebocoran memori atau pengelolaan sumber daya yang rumit.

Arsitektur per-process garbage collection inilah yang membuat sistem berbasis Elixir dapat berjalan terus-menerus selama bertahun-tahun tanpa perlu dimatikan atau restart.

Referensi

  • Jurić, S. (2024). Elixir in Action (3rd ed.). Manning Publications.

Top comments (0)