Daftar Isi
- Pendahuluan
- Modul
- Fungsi
- Ariti Fungsi
- Fungsi Dengan Parameter Default
- Visibilitas Fungsi
- Import Dan Alias
- Atribut Modul
- Komentar
- Referensi
Pendahuluan
Elixir adalah bahasa pemrograman fungsional yang mengandalkan fungsi untuk menangani data yang bersifat tidak dapat diubah (immutability). Fungsi-fungsi ini dikelompokkan ke dalam modul. Modul berfungsi sebagai wadah untuk mengorganisasi fungsi-fungsi terkait dan memudahkan pengelolaan dan penggunaan kode. Setiap modul dapat berisi satu atau lebih fungsi yang dapat dipanggil untuk berbagai operasi.
Modul
Modul di Elixir berfungsi sebagai wadah untuk kumpulan fungsi terkait, mirip dengan namespace dalam bahasa pemrograman lain. Setiap fungsi dalam Elixir harus didefinisikan di dalam modul, dan modul didefinisikan menggunakan konvensi penulisan CamelCase.
Sebagai contoh, Elixir menyediakan modul standar IO
untuk operasi I/O. Fungsi puts
berada di dalam modul IO
yang kita dapat digunakan untuk menampilkan pesan ke layar:
iex(1)> IO.puts("Halo Dunia!") ❶
Halo Dunia! ❷
:ok ❸
Penjelasan kode di atas adalah sebagai berikut:
- Memanggil fungsi
puts
dari modulIO
. - Fungsi
IO.puts
mencetak "Halo Dunia!" ke layar. - Nilai kembalian dari
IO.puts
adalah:ok
.
Kode tersebut menunjukkan bahwa untuk memanggil fungsi dari modul kita menggunakan sintaks NamaModul.nama_fungsi(argumen_1, argumen_n)
.
Mendefinisikan Modul Sendiri
Untuk mendefinisikan modul sendiri, kita menggunakan defmodule
, dan fungsi di dalamnya didefinisikan menggunakan def
, berikut contohnya:
Listing: Mendefinisikan sebuah modul (geometry.ex)
defmodule Geometry do ❶
def rectangle_area(length, width) do ❷
length * width
end
end ❸
Penjelasan kode di atas adalah:
- Mendefinisikan sebuah modul bernama
Geometry
. - Di dalam modul, kita mendefiniskan sebuah fungsi bernama
rectangle_area
dan diakhiri dengan ekspresiend
untuk menandakan akhir dari tubuh fungsi. - Modul ditutup dengan ekspresi
end
.
Modul ini dapat diuji langsung dalam iex
dengan menginterpretasikan berkasnya:
$ iex geometry.ex ❶
iex(1)> Geometry.rectangle_area(6, 7) ❷
42 ❸
Penjelasan kode di atas adalah sebagai berikut:
- Menjalankan
iex
dan memuat modulGeometry
dari filegeometry.ex
ke dalam sesi interactive shell. - Memanggil fungsi
rectangle_area
dari modulGeometry
dengan argumen 6 dan 7. - Hasil dari fungsi tersebut adalah 42.
Dengan mendefinisikan modul ini, kita dapat memuatnya ke dalam sesi shell Elixir dan menggunakan fungsinya untuk menghitung luas persegi panjang.
Dalam source code Elixir, modul biasanya didefinisikan dalam satu file dengan ekstensi .ex
, tetapi satu file dapat berisi lebih dari satu modul.
defmodule Geometry do
defmodule Rectangle do
...
end
end
Dalam Elixir, modul yang berada di dalam modul lain bisa diakses dengan notasi seperti Geometry.Rectangle
. Titik (.
) dalam nama modul tidak memiliki makna khusus, melainkan hanya digunakan sebagai karakter pemisah dalam nama modul. Ketika kode dikompilasi, tidak ada informasi tentang hubungan hierarki antara modul yang disimpan.
Penggunaan notasi hierarki ini berguna untuk mengatur modul dengan cara yang lebih terstruktur dan memudahkan navigasi kode. Misalnya, jika ada dua pustaka berbeda, satu untuk encoding JSON dan satu lagi untuk encoding XML, keduanya mungkin memiliki modul dengan nama Encoder
. Jika kedua pustaka ini digunakan dalam proyek yang sama, nama modul yang sama akan menyebabkan konflik. Namun, jika nama modul diubah menjadi Json.Encoder
dan Xml.Encoder
, konflik nama dapat dihindari.
Oleh karena itu, biasanya nama aplikasi atau pustaka digunakan sebagai awalan untuk menghindari bentrok nama dan membuat organisasi kode lebih jelas.
Fungsi
Fungsi merupakan bagian penting dari setiap modul di Elixir. Konvensi penamaan fungsi di Elixir mengikuti aturan serupa dengan variabel:
- Nama fungsi harus dimulai dengan huruf kecil atau garis bawah (
_
). - Setelah karakter pertama, nama fungsi dapat terdiri dari kombinasi huruf, angka, dan garis bawah.
- Fungsi dapat diakhiri dengan tanda tanya (
?
) untuk menandai bahwa fungsi tersebut mengembalikan nilai boolean (true
ataufalse
), atau tanda seru (!
) untuk menunjukkan bahwa fungsi tersebut mungkin memiliki efek samping atau dapat memicu kesalahan.
Pentingnya Simbol Dalam Penamaan Fungsi
Fungsi di Elixir dapat diakhiri dengan tanda tanya (?
) atau tanda seru (!
). Tanda tanya (?
) digunakan untuk fungsi yang mengembalikan nilai boolean (true atau false), yang mencerminkan pertanyaan—apakah suatu kondisi terpenuhi. Sebaliknya, tanda seru (!
) digunakan untuk fungsi yang mungkin memicu kesalahan runtime, menandakan potensi efek samping yang serius atau kesalahan yang tidak terduga. Mengikuti konvensi ini dapat membantu kita menjaga konsistensi dan memudahkan pemahaman fungsi bagi pengembang lain.
Mendefinisikan Fungsi
Untuk mendefinisikan fungsi dalam Elixir, kita menggunakan makro def
di dalam blok defmodule
. Berikut adalah struktur dasar untuk mendefinisikan fungsi:
defmodule Geometry do
def rectangle_area(a, b) do ❶
# tubuh fungsi ❷
end
end
Penjelasan kode di atas adalah:
-
def rectangle_area(a, b) do
mendefinisikan fungsirectangle_area
dengan dua argumen,a
danb
. - Tubuh fungsi adalah bagian antara blok
do
danend
, di sinilah kode fungsi ditulis.
Pada contoh di atas, rectangle_area
adalah fungsi yang menghitung area dari sebuah persegi panjang. Penggunaan def
diikuti oleh nama fungsi dan argumen yang dibutuhkan, serta diapit oleh blok do...end
yang menandakan awal dan akhir dari definisi fungsi.
Jika sebuah fungsi tidak memerlukan argumen, tanda kurung dapat dihilangkan dalam definisinya, memperjelas bahwa fungsi tersebut tidak memerlukan input argumen:
defmodule Program do
def run do
# Implementasi fungsi
end
end
Nilai Pengembalian Fungsi
Di Elixir, konsep nilai pengembalian fungsi berbeda dari beberapa bahasa pemrograman lain yang menggunakan kata kunci return
secara eksplisit. Di bahasa ini, setiap fungsi secara otomatis mengembalikan nilai dari ekspresi terakhir yang dievaluasi di dalamnya.
Mari kita lihat contoh fungsi yang menghitung luas persegi panjang berikut:
defmodule Geometry do
def rectangle_area(a, b) do
a * b
end
end
Dalam contoh di atas, ekspresi a * b
adalah ekspresi terakhir yang dievaluasi di dalam fungsi rectangle_area
. Nilai dari ekspresi ini secara otomatis dikembalikan sebagai hasil dari fungsi tersebut, tanpa memerlukan kata kunci return
.
Mendefinisikan Fungsi Dalam Satu Baris
Jika tubuh fungsi hanya terdiri dari satu ekspresi dan tidak memerlukan logika tambahan, kita dapat menggunakan sintaks alternatif yang lebih ringkas:
defmodule Geometry do
def rectangle_area(a, b), do: a * b
end
Sintaks ini efektif untuk fungsi sederhana yang langsung mengembalikan hasil dari satu ekspresi, menjadikan kode lebih bersih dan mudah untuk dibaca. Tentu saja jika kita menjalankannya di interactive shell hasilnya sama dengan versi fungsi yang sebelumnya.
Memanggil Fungsi Antar Modul Yang Berbeda
Untuk memanggil fungsi dari modul lain, gunakan nama modul diikuti dengan nama fungsinya:
iex(1)> Geometry.rectangle_area(3, 2) ❶
6
iex(2)> area = Geometry.rectangle_area(3, 2) ❷
6
iex(3)> area ❸
6
Penjelasan kode di atas adalah:
- Memanggil fungsi
rectangle_area
dari modulGeometry
. - Fungsi dapat disimpan dalam variabel, sesuai dengan prinsip first-class function.
- Memverifikasi nilai variabel
area
, yang merupakan hasil dari fungsiGeometry.rectangle_area
.
Memanggil Fungsi Dalam Modul Yang Sama
Ketika sebuah fungsi dipanggil dari modul yang sama, kita tidak perlu menyertakan nama modul di depannya. Ini mengurangi redundansi dan mempertahankan kejelasan kode:
defmodule Geometry do
def rectangle_area(a, b) do ❶
a * b
end
def square_area(a) do ❷
rectangle_area(a, a)
end
end
Penjelasan kode di atas adalah:
- Mendefinisikan fungsi
rectangle_area
. - Mendefinisikan fungsi
square_area
, yang memanggil fungsirectangle_area
tanpa menyertakan nama modulnya karena berada dalam modul yang sama.
Praktek ini umum dalam Elixir untuk meningkatkan keterbacaan dan memudahkan manajemen kode internal modul. Memahami cara memanggil fungsi dengan benar sangat penting untuk mengelola proyek Elixir yang besar, di mana modul dan fungsi bisa sangat banyak dan kompleks.
Menggunakan Pipe Operator
Pipe Operator |>
di Elixir sangat berguna untuk menyusun fungsi secara berantai, ini membuat alur kode kita lebih mudah dibaca. Operator ini mengalirkan hasil dari satu fungsi sebagai argumen pertama ke fungsi berikutnya, seperti dalam contoh berikut:
iex(5)> -5 |> abs() |> Integer.to_string() |> IO.puts()
5
Dalam contoh di atas, nilai -5
diubah menjadi angka positif dengan fungsi abs()
, kemudian diubah menjadi string oleh fungsi Integer.to_string()
, dan terakhir dicetak ke terminal dengan fungsi IO.puts()
. Penggunaan pipe operator memudahkan pemahaman alur data melalui fungsi-fungsi ini.
Saat dikompilasi, kode di atas akan diubah menjadi fungsi yang disusun menggunakan teknik staircasing:
iex(6)> IO.puts(Integer.to_string(abs(-5)))
5
Untuk meningkatkan keterbacaan kode, kita juga bisa menyusun penggunaan pipe operator dalam beberapa baris:
-5
|> abs()
|> Integer.to_string()
|> IO.puts()
Penyusunan fungsi seperti ini membantu melacak transformasi data langkah demi langkah, dengan kode dibaca dari kiri ke kanan atau dari atas ke bawah.
Ariti Fungsi
Ariti dalam Elixir merujuk pada jumlah argumen yang diterima oleh sebuah fungsi. Fungsi di Elixir dapat diidentifikasi tidak hanya berdasarkan nama fungsi dan nama modulnya, tetapi juga berdasarkan ariti—jumlah argumen yang diterima.
Sebagai contoh, lihat fungsi area
dalam modul Rectangle
:
defmodule Rectangle do
def area(a, b) do
a * b
end
end
Fungsi Rectangle.area
memiliki dua argumen, sehingga aritinya adalah 2. Dalam dokumentasi dan kode Elixir, fungsi ini sering dirujuk sebagai Rectangle.area/2
.
Pentingnya Ariti
Kenapa ariti itu penting? Di Elixir, dua fungsi dengan nama yang sama tetapi jumlah argumen yang berbeda dianggap sebagai fungsi yang berbeda. Ariti membantu membedakan fungsi-fungsi tersebut dan memastikan mereka dipanggil dengan cara yang benar. Mari kita lihat contohnya:
Listing: Ariti Fungsi (arity.ex)
defmodule Rectangle do
def area(a), do: area(a, a)
def area(a, b), do: a * b
end
Pada contoh kode di atas, modul Rectangle
memiliki dua fungsi dengan nama yang sama, yaitu area
. Namun, fungsi ini memiliki jumlah argumen yang berbeda: satu dengan 1 argumen (ariti 1) dan lainnya dengan 2 argumen (ariti 2). Fungsi pertama disebut Rectangle.area/1
, sedangkan fungsi kedua disebut Rectangle.area/2
. Ini berarti kedua fungsi tersebut dianggap berbeda karena jumlah argumen yang mereka terima.
Sekarang, mari kita coba kedua fungsi tersebut. Muat modul di atas ke dalam iex
, lalu panggil fungsinya seperti ini:
iex(1)> Rectangle.area(5)
25
iex(2)> Rectangle.area(5,6)
30
Seperti yang terlihat, kedua fungsi ini berfungsi dengan cara yang berbeda. Nama fungsinya sama, tetapi jumlah argumennya berbeda, sehingga dianggap sebagai dua fungsi yang berbeda, masing-masing dengan implementasinya sendiri.
Biasanya, tidak masuk akal jika dua fungsi dengan nama yang sama memiliki implementasi yang sepenuhnya berbeda. umumnya, fungsi dengan ariti yang lebih rendah mendelegasikan tugasnya ke fungsi dengan ariti yang lebih tinggi dengan memberikan beberapa argumen default. Dalam implementasi di atas, Rectangle.area/1
mendelegasikan tugasnya ke Rectangle.area/2
.
Mari kita lihat contoh lainnya:
Listing: Ariti Fungsi (anothe_arity.ex)
defmodule Calculator do
def add(a), do: add(a, 0) ❶
def add(a, b), do: a + b ❷
end
Penjelasan kode di atas adalah:
- Fungsi
Calculator.add/1
mendelegasikan tugasnya ke fungsiCalculator.add/2
dengan memberikan argumen default0
untuk argumen kedua. - Fungsi
Calculator.add/2
melakukan operasi penjumlahan sesuai dengan implementasinya.
Fungsi Dengan Parameter Default
Elixir mendukung parameter default yang memungkinkan kita mengurangi jumlah fungsi yang perlu kita ditulis:
defmodule Calculator do
def add(a, b \\ 0), do: a + b ❶
end
Dalam kode di atas, fungsi Calculator.add/2
mendefinisikan nilai default 0
untuk argumen b
.
Penggunaan parameter default pada suatu fungsi dapat menghasilkan variasi fungsi dengan ariti yang berbeda dari definisi tunggal. Sebagai contoh:
defmodule MyModule do
def fun(arg1, arg2 \\ 1, arg3, arg4 \\ 2) do ❶
arg1 + arg2 + arg3 + arg4
end
end
Dalam kode di atas, fungsi MyModule.fun/4
secara otomatis menghasilkan beberapa versi fungsi berdasarkan kombinasi argumen yang diterima dan argumen default:
def fun(arg1, arg3), do: fun(arg1, 1, arg3, 2)
def fun(arg1, arg2, arg3), do: fun(arg1, arg2, arg3, 2)
def fun(arg1, arg2, arg3, arg4), do: arg1 + arg2 + arg3 + arg4
Karena ariti membedakan fungsi-fungsi dengan nama yang sama, tidak memungkinkan untuk memiliki fungsi yang menerima jumlah argumen variabel. Elixir tidak memiliki padanan dari ...
di bahasa C atau arguments
di JavaScript, sehingga membantu menjaga kejelasan dalam definisi dan penggunaan fungsi.
Visibilitas Fungsi
Dalam Elixir, visibilitas fungsi diatur dengan dua makro: def
dan defp
. Makro ini membedakan antara fungsi yang dapat diakses secara publik dan fungsi yang bersifat privat.
Fungsi Publik Dan Privat
-
Fungsi Publik: Didefinisikan menggunakan
def
, fungsi publik dapat dipanggil dari modul lain atau dari sesi interactive shell. Ini memungkinkan fungsi tersebut diakses secara luas. -
Fungsi Privat: Didefinikan menggunakan
defp
, fungsi privat hanya dapat dipanggil dari dalam modul tempat mereka didefinisikan. Fungsi privat mendukung fungsi publik dalam modul itu sendiri atau menyelesaikan tugas internal yang tidak perlu diungkapkan ke luar.
Mari kita lihat contoh berikut implementasi dari kedua jenis fungsi ini:
Listing: Fungsi Publik Dan Privat (public_private_function.ex)
defmodule TestPrivate do
def double(a) do ❶
sum(a, a) ❷
end
defp sum(a, b) do ❸
a + b
end
end
Penjelasan kode di atas adalah:
- Mendefinisikan fungsi publik
double/1
. - Dalam tubuh fungsi
double/1
, memanggil fungsi privatsum/2
. - Mendefinisikan fungsi privat
sum/2
.
Dalam kode di atas, modul TestPrivate
mendefinisikan fungsi publik double/2
yang mengunakan fungsi privat sum/2
untuk menghitung dua kali nilai dari argumen yang diberikan. Fungsi sum/2
bersifat privat dan hanya digunakan sebagai pembantu untuk fungsi doule/2
.
Menguji Visibilitas Fungsi
Ketika kita mencoba memanggil fungsi ini dari interactive shell Elixir, kita akan melihat perbedaan dalam visibilitas:
iex(1)> TestPrivate.double(3)
6 # Fungsi publik `double` berhasil dipanggil
iex(2)> TestPrivate.sum(3, 4)
** (UndefinedFunctionError) function TestPrivate.sum/2 is private
...
Pada baris kedua interactive shell, saat kita memanggil fungsi sum/2
maka akan muncul pesan UndefinedFunctionError
, ini terjadi karena fungsi ini bersifat privat dan tidak dapat diakses dari luar modulnya.
Pentingnya Enkapsulasi
Pemisahan antara fungsi publik dan privat penting untuk konsep enkapsulasi dalam pemrograman fungsional. Dengan membatasi akses ke fungsi-fungsi tertentu, modul dapat menyembunyikan detail implementasi internalnya, memungkinkan pemanggil fokus pada fungsionalitas modul tanpa perlu memikirkan implementasinya. Ini membantu menjaga kebersihan dan pemeliharaan kode.
Fungsi privat juga mengurangi kemungkinan penggunaan yang tidak tepat oleh bagian kode lain, yang dapat menyebabkan bug sulit ditelusuri. Penggunaan defp
untuk fungsi privat memperjelas bahwa fungsi tersebut hanya dimaksudkan untuk digunakan secara internal dalam modul.
Import Dan Alias
Dalam Elixir, untuk memudahkan dan mempersingkat kode saat bekerja dengan modul lain, kita dapat menggunakan dua cara yaitu menggunakan import
dan alias
. Kedua ini memungkinkan kita untuk merujuk fungsi atau modul dengan cara yang lebih sederhana dan efisien.
Menggunakan Import
Ketika kita mengimpor modul, kita dapat memangil fungsi publiknya tanpa perlu menyertakan nama modulnya setiap kali:
defmodule MyModule do
import IO ❶
def my_function do
puts "Calling imported function." ❷
end
end
Penjelasan kode di atas:
- Mengimpor modul
IO
ke dalam modulMyModule
. - Memanggil fungsi
puts
tanpa harus menulis prefixIO.
Dengan mengimpor modul IO
, kita bisa langsung menggunakan fungsi puts
tanpa perlu menuliskan IO.puts
. Ini sangat membantu, terutama ketika kita sering menggunakan fungsi dari modul yang diimpor dalam kode yang kita tulis.
Menggunakan Alias
alias
memungkinkan kita memberikan nama alternatif (alias) untuk modul, yang sangat berguna jika modul tersebut memiliki nama panjang atau jika kita ingin menggunakan nama yang lebih singkat atau deskriptif:
defmodule MyModule do
alias IO, as: MyIO ❶
def my_function do
MyIO.puts("Calling imported function.") ❷
end
end
Penjelasan kode di atas:
- Membuat alias
MyIO
untuk modulIO
. - Memanggil fungsi menggunakan alias
MyIO
alih-alihIO
.
Di sini, kita memberikan alias MyIO
untuk modul IO
, sehingga kita dapat menggunakan MyIO.puts
alih-alih IO.puts
, yang dapat meningkatkan kejelasan kode tergantung pada konteks pemrograman kita.
Kita juga bisa menggunakan alias
tanpa opsi as:
, yang akan menggunakan bagian terakhir dari nama modul sebagai alias. Berikut contohnya:
defmodule MyModule do
alias Geometry.Rectangle ❶
def my_function do
Rectangle.area(...) ❷
end
end
Penjelasan kode di atas:
- Membuat alias
Rectangle
untuk modulGeometry.Rectangle
. - Memanggil fungsi
area
menggunakan aliasRectangle
.
Umumnya, developer Elixir memberikan alias kepada modul hanya dengan bagian terakhir dari namanya untuk menyederhanakan referensi.
Pentingnya Import Dan Alias
- Kemudahan Akses: Mengurangi kebutuhan untuk menuliskan nama modul secara lengkap setiap kali memanggil fungsi, yang bisa sangat membantu dalam modul yang sering digunakan atau memiliki nama panjang.
- Menghindari Redundansi: Membantu menghindari pengulangan nama modul yang tidak perlu dan membuat kode lebih ringkas.
- Kejelasan dan Konteks: Alias dapat memberikan konteks tambahan atau mengklarifikasi penggunaan modul tertentu dalam kode kita, terutama jika nama modul asli kurang jelas atau terlalu umum.
Penggunaan import
dan alias
adalah praktek pengembangan yang baik dalam Elixir karena membantu mempertahankan kode yang terorganisir, mudah dipahami, dan mudah dipelihara.
Atribut Modul
Atribut modul dalam Elixir memainkan peran penting dalam pengaturan konstanta pada waktu kompilasi (compile-time) dan penyediaan informasi yang dapat diakses selama runtime. Keduanya memperkaya modularitas dan dokumentasi kode.
Kontanta Pada Waktu Kompilasi
Atribut modul dapat digunakan sebagai konstanta pada waktu kompilasi:
defmodule Circle do
@pi 3.14159 ❶
def area(r), do: r * r * @pi ❷
def circumference(r), do: 2 * r * @pi
end
iex(1)> Circle.area(1) # Hasil: 3.14159
iex(2)> Circle.circumference(1) # Hasil: 6.28318
Penjelasan kode di atas adalah:
- Mendefinisikan atribut
@pi
. - Menggunakan atribut
@pi
sebagai konstanta dalam fungsi.
Dalam contoh kode di atas, @pi
didefinisikan sebagai konstanta dalam modul Circle
. Fungsi dalam modul ini menggunakan @pi
yang nilainya ditetapkan selama kompilasi.
Informasi Yang Dapat Diakses Saat Runtime
Atribut modul juga bisa menyimpan dokumentasi yang dapat diakses selama runtime:
defmodule Circle do
@moduledoc "Menyediakan fungsi dasar untuk operasi lingkaran"
@pi 3.14159
@doc "Menghitung luas lingkaran"
def area(r), do: r * r * @pi
@doc "Menghitung keliling lingkaran"
def circumference(r), do: 2 * r * @pi
end
Penggunaan @moduledoc
dan @doc
memberikan konteks dan penjelasan tentang modul dan fungsinya yang dapat diakses melalui alat bantu seperti iex
:
iex(1)> h Circle # Menampilkan dokumentasi untuk modul Circle
iex(2)> h Circle.area # Menampilkan dokumentasi untuk fungsi area
Mendaftarkan Atribut
Atribut modul tidak hanya terbatas pada dokumentasi. Kita bisa mendefinisikan atribut khusus yang digunakan dalam logika internal modul atau untuk keperluan refleksi:
defmodule Example do
@my_attribute "Important data"
def get_attribute, do: @my_attribute
end
Di sini, @my_attribute
menunjukkan bagaimana atribut dapat ditetapkan dan diakses dalam modul yang sama.
Atribut modul dalam Elixir sangat fleksibel dan digunakan untuk berbagai keperluan, mulai dari mendefinisikan konstanta waktu kompilasi hingga menyimpan metadata yang bisa diakses selama runtime. Ini merupakan bagian penting dari struktur kode dalam Elixir yang meningkatkan modularitas, kejelasan, dan kemudahan penggunaan. Informasi lebih lanjut mengenai penggunaan atribut modul dapat ditemukan di dokumentasi Elixir.
Typespecs
Spesifikasi tipe atau typespecs di Elixir memungkinkan kita untuk mendefinisikan tipe data yang diterima oleh argumen dan dikembalikan oleh fungsi. Ini membantu dalam dokumentasi serta analisis statis kode melalui alat seperti Dialyzer, dan juga meningkatkan keamanan kode dengan memverifikasi kecocokan tipe data secara statis sebelum runtime.
Mari kita perhatikan bagaimana typespecs diimplementasikan dalam modul Circle
yang menyediakan fungsi operasi dasar untuk lingkaran:
defmodule Circle do
@pi 3.14159
@spec area(number()) :: number() ❶
def area(r), do: r * r * @pi
@spec circumference(number()) :: number() ❷
def circumference(r), do: 2 * r * @pi
end
Dalam contoh kode di atas, kita menggunakan atribut @spec
untuk menunjukkan bahwa kedua fungsi, area
dan circumference
, menerima dan mengembalikan tipe data number()
. Ini memberikan kejelasan bahwa fungsi-fungsi ini bekerja dengan angka dan menghasilkan angka, ini membantu memastikan bahwa tipe data yang diproses sesuai dengan yang diharapkan.
Typespecs adalah cara untuk memberikan informasi tentang jenis data yang diterima dan dikembalikan oleh fungsi. Ini berfungsi mirip dengan komentar yang menjelaskan bagaimana fungsi seharusnya digunakan. Dengan typespecs, kita bisa mendokumentasikan fungsi dengan lebih jelas, sehingga lebih mudah bagi pengembang lain untuk memahami kode kita.
Elixir adalah bahasa pemrograman dinamis, yang berarti bahwa jenis data tidak selalu diperiksa secara ketat selama penulisan kode. Typespecs membantu mengatasi hal ini dengan memberikan penjelasan eksplisit tentang jenis data yang digunakan, yang bisa sangat berguna ketika bekerja dengan kode yang kompleks atau saat berkolaborasi dengan orang lain.
Sebagai contoh, lihat typespec untuk fungsi Elixir List.insert_at/3
:
@spec insert_at(list, integer, any) :: list
Typespec ini menunjukkan bahwa fungsi insert_at
menerima tiga argumen: sebuah list, sebuah integer yang menunjukkan posisi, dan sebuah nilai dari tipe apa pun. Fungsi ini kemudian mengembalikan list baru. Meskipun tanpa melihat implementasi atau dokumentasi, typespec ini memberikan kita pemahaman yang jelas tentang apa yang dilakukan fungsi tersebut dan bagaimana cara kerjanya.
Typespecs meningkatkan kejelasan dan membantu dalam memeriksa kesalahan pada waktu kompilasi, membuat kode lebih mudah dipahami dan dikelola. Untuk informasi lebih lanjut tentang typespecs, kita dapat membacanya di dokumentasi Elixir.
Komentar
Dalam Elixir, komentar merupakan bagian penting dari kode yang membantu menjelaskan fungsi, tujuan, atau alasan di balik potongan kode tertentu, serta untuk menonaktifkan sementara kode tanpa menghapusnya.
Elixir hanya mendukung komentar satu baris, di mana semua teks setelah tanda pagar (#
) pada baris tersebut akan diabaikan oleh compiler. Jika perlu mengomentari beberapa baris, setiap baris harus dimulai dengan #
:
# Ini adalah komentar yang menjelaskan kode
a = 3.14 # Ini juga komentar yang mengikuti kode
# Ini adalah cara untuk mengomentari beberapa baris
# dengan menambahkan # di setiap baris.
# Semua baris dengan # akan dianggap komentar.
Referensi
- Juric, S. (2024). Elixir in Action (3rd ed.). Manning Publications.
Top comments (0)