• Tidak ada hasil yang ditemukan

BAB 8 KOMIPLASI, EKSEKUSI DAN KESALAHAN

8.1 Fungsi require

Lua memberikan sebuah fungsi tingkat tinggi untuk memanggil dan menjalankan

pustaka,yang disebut require. Secara kasar require,sama dengan dofile,tetapi ada 2

perbedaan penting. Pertama,require mencari file dalam sebuah path,kedua,require

mengontrol apakah sebuah file sudah dijalankan untuk menghindari duplikasi pekerjaan. Karena fitur ini,require dipilih sebagai fungsi dalam Lua untuk memanggil pustaka.

Path yang digunakan oleh require sedikit berbeda dari path yang biasa. Kebanyakan program menggunakan paths sebagai sebuah daftar direktori yang digunakan untuk mencari file yang dibutuhkan. Tetapi,ANSI C tidak punya konsep direktori. Oleh karena itu,path yang

digunakan oleh require adalah daftar patterns, berisi spesifikasi sebuah jalur untuk

mentransformasi sebuah nama file virtual kedalam nama yang sebenarnya. Lebih spesifik lagi,setiap komponen dalam path adalah file yang mengandung tanda Tanya pilihan. Untuk setiap komponen

require mengganti setiap ‘?’ dengan nama file virtual dan mengecek apakah ada file dengan nama tersebut; jika tidak,akan dilakukan pengecekan pada komponen selanjutnya. Komponen dalam sebuah path dibagi-bagi oleh “;”. Untuk contoh,jika pathnya adalah:

?;?.lua;c:\windows\?;/usr/local/lua/?/?.lua

Kemudian memanggil require“lili” akan mencoba untuk membuka file dibawah ini:

lili

lili.lua c:\windows\lili

/usr/local/lua/lili/lili.lua

Hanya tanda ; dan ? yang diganti oleh require. Segala sesuatunya didefinisikan dalam path.

Untuk menentukan path tersebut, require pertama kali memeriksa variabel global LUA_PATH. Jika nilai LUA_PATH adalah sebuah string,string inilah yang disebut path. Jika tidak,require memeriksa variabel lingkungan LUA_PATH. Terakhir,jika kedua pemeriksaan gagal,require menggunakan sebuah path tetap.

Pekerjaan utama yang lain dari require adalah mencegah pemanggilan file yang sama,2 kali. Untuk kepentingan ini,require berpedoman pada sebuah tabel dengan nama seluruh file yang dipanggil. Jika sebuah file yang dibutuhkan sudah ada dalam tabel,require dengan mudah mengembalikannya. Tabel menyimpan nama virtual dari file yang dipanggil,bukan nama sebenarnya.oleh karena itu,jika kamu memanggil file yang sama dengan 2 nama virtual yang berbeda,ini akan dipanggil 2 kali. Sebagai contoh perintah require “foo” diikuti oleh require

“foo.lua”,dengan sebuah path seperti “?;?.lua”,akan memanggil file foo.lua 2 kali. Kamu dapat mengakses tabel pengaturan melalui variabel global _LOADED. Menggunakan tabel ini,kamu dapat memeriksa file mana yang sudah dipanggil; Kamu juga dapat mempermainkan require untuk menjalankan file 2 kali. Sebagai contoh,setelah selesai require

“foo”,_LOADED[“foo”] tidak akan nil. Jika kamu kemudian menunjuk nil ke _LOADED[“foo”] kemudian require “foo” akan menjalankan file lagi.

Sebuah komponen tidak butuh tanda ?; ini dapat berupa nama file yang tetap ,seperti komponen terakhir pada path dibawah ini:

?;?.lua;/usr/local/default.lua

Pada pilihan ini,jika require tidak mendapatkan pilihan lain,program akan menjalankan file

tetap. Sebelum require menjalankan sebuah kode,require mendefiniskan variabel global

_REQUIREDNAME yang mengandung nama virtual dari file yang dibutuhkan. Kita dapat menggunakan fasilitas ini untuk memperluas fungsionalitas require. Dalam contoh yang ekstrim,kita boleh mengatur suatu path seperti “/usr/local/lua/newrequire.lua”,jadi setiap panggilan

require menjalankan newrequire.lua,yang mana dapat digunakan sebagai nilai dari _REQUIREDNAME untuk memanggil file yang dibutuhkan.

8.2 Paket C

Karena mudahnya menggabungkan Lua dengan C,ini juga mudah untuk menulis paket untuk Lua di C. Tidak seperti paket yang ditulis dalam LUA,tetapi,paket C butuh dipanggil dan dihubungkan dengan sebuah aplikasi sebelum digunakan. Dalam sistem yang sangat terkenal,jalur yang mudah untuk melakukan ini adalah dengan fasilitas hubungan dinamis. Tetapi,fasilitas ini bukan bagian dari spesifikasi ANSI C; tidak ada jalur portable untuk implementasi ini.

Biasanya,Lua tidak berisi fasilitas yang tidak bisa diimplementasikan dalam ANSI C. Tetapi,hubungan dinamis berbeda. Kita dapat melihat ini sebagai induk dari semua fasilitas. Satu lagi yang kita punya,kita dapat memanggil secara dinamis fasilitas lain yang tidak terdapat di Lua. Oleh karena itu,ini adalah pilihan istimewa. Lua mematahkan aturan kompatibilitas dan mengimplementasikan fasilitas hubungan dinamis untuk beberapa platform,menggunakan conditional code. Standar implementasi yang ditawarkan adalah dukungan untuk windows(dll),Linux,FreeBSD,Solaris dan beberapa implementasi UNIX. Ini seharusnya tidak sulit untuk menurunkan fasilitas ini ke platform lain; Periksa distribusi kamu(untuk memeriksa ini,jalankan print (loadlib()) dari Prompt Lua dan lihat hasilnya. Jika menghasilkan bad argument,berarti kamu punya fasilitas hubungan dinamis. Jika tidak,menandakan bahwa fasilitas tidak didukung atau tidak diinstall.)

Lua memberikan seluruh fungsionalitas hubungan dinamis dalam fungsi tunggal yang

disebut loadlib.ini mempunyai 2 argumen string;path lengkap pustaka dan nama fungsi

inisialisasi. Jadi,pemanggilnya seperti dibawah ini:

Local path= "/usr/local/lua/lib/libluasocket.so" local f = loadlib(path, "luaopen_socket")

Fungsi loadlib memanggil pustaka yang diberikan dan menghubungkan Lua dengan

pustaka tetapi bukan untuk membuka pustaka: ini mengembalikan fungsi inisialisasi sebagai fungsi Lua,jadi kita dapat memanggil langsung dari Lua. Jika ada kesalahan pemanggilan pustaka atau mendapatkan inisialisai fungsi,loadlib mengembalikan nil ditambah sebuah pesan kesalahan. Kita dapat menambah bagian sebelumnya untuk memeriksa kesalahan dan memanggil fungsi inisialisasi:

Local path = "/usr/local/lua/lib/libluasocket.so" -- or path = "C:\\windows\\luasocket.dll" local f = assert(loadlib(path, "luaopen_socket"))

Biasanya,kita dapat mengharapkan sebuah distribusi pustaka untuk mengisi file utama yang sama dengan bagian sebelumnya. Kemudian,untuk menginstall pustaka,kita letakkan pustaka binary dimana saja,edit file untuk merujuk ke path sebenarnya dan kemudian tambahkan file utama tersebut kedalam direktori yang ada pada LUA_PATH. Dengan pengaturan ini,kita dapat menggunakan fungsi require untuk membuka pustaka C.

8.3 Kesalahan

Errare Humanum est. Oleh karena itu,kita harus menangani kesalahan dengan sebaik mungkin karena Lua adalah Bahasa besar,sering ditanam dalam sebuah aplikasi,ini tidak mudah rusak atau keluar dari program ketika kesalahan terjadi,Lua mengakhiri kode yang dijalankan dan kembali ke aplikasi.

Ada beberapa kondisi yang tidak diharapkan yang membuat Lua menampilkan kesalahan- kesalahan,terjadi ketika kamu mencoba untuk menambahkan nilai ke variabel non numeric,memanggil nilai yang dihasilkan bukan dari fungsi,mengindeks nilai yang tidak ada pada tabel,dll. Kamu juga dapat menampilkan error dengan memanggil fungsi error; Argumennya adalah pesan kesalahan. Biasanya,fungsi ini bukan jalan yang baik untuk menangani kesalahan pada kode anda:

print "enter a number:" n = io.read("*number")

if not n then error("invalid input") end

Demikian kombinasi if not … then error end terlalu umum,Lua memiliki fungsi sendiri untuk melakukan pekerjaan ini,cukup memanggil assert:

print "enter a number:"

n = assert(io.read("*number"), "invalid input")

Fungsi assert memeriksa apakah argument pertama tidak salah dan mengembalikan

argument tersebut; Jika argument salah,assert akan menampilkan kesalahan. Argumen

kedua,pesan kesalahan,sifatnya optional. Jadi,jika kamu tidak ingin mengatakan sesuatu dalam pesan kesalahan,kamu tidak perlu menuliskan pesan tersebut. Hati-hati,assert adalah fungsi biasa. Dengan demikian Lua selalu mengevaluasi argument ini sebelum memanggil fungsi. Oleh karena itu,jika kamu punya sesuatu seperti

n = io.read()

assert(tonumber(n),

"invalid input: " .. n .. " is not a number")

Lua akan selalu menggabungkan,sama ketika n sebuah angka. Ini mungkin mengharapkan untuk menggunakan sebuah tes nyata dalam beberapa pilihan.

Ketika sebuah fungsi mendapatkan situasi yang tidak diinginkan,ini dapat menghasilkan 2 perilaku dasar:mengembalikan kode error atau menampilkan error,panggil fungsi error. Disini tidak ada aturan tetap untuk memilih diantara keduanya,tetapi kita dapat memberikan sebuah garis petunjuk: Sebuah exception biasanya lebih mudah dihindari dengan menampilkan kode error: Jika tidak,ini seharusnya mengembalikan sebuah kode error.

Sebagai contoh,lihat fungsi sin dibawah ini. Bagaimana seharusnya ini berkelakuan ketika memanggil sebuah tabel? Mungkin ini mengembalikan sebuah kode error. Jika kita butuh untuk memeriksa kesalahan,kita seharusnya menulis seperti ini:

local res = math.sin(x) if not res then -- error ...

Tetapi,kita dapat dengan mudah memeriksa exception ini sebelum memanggil fungsi:

if not tonumber(x) then -- error: x is not a number ...

Biasanya, kita tidak memeriksa keduanya baik argumen maupun hasil pemanggilan

sin;Jika argumen bukan angka,ini artinya terjadi suatu kesalahan dalam program. Dalam beberapa situasi,untuk menghentikan proses komputasi dan untuk menghasilkan pesan kesalahan lebih mudah dan banyak digunakan dalam praktek untuk menangani exception.

Pada contoh lain,kita akan mencoba fungsi io.open,yang akan membuka sebuah file. Bagaimana seharusnya fungsi ini berkelakuan ketika dipanggil sebuah file yang tidak ada? Dalam kasus ini,tidak ada jalur yang mudah untuk memeriksa exception sebelum memanggil fungsi. Dalam banyak sistem kita hanya bisa mengetahui apakah sebuah file yang ada bisa dibuka. Oleh karena itu,jika io.open tidak bisa membuka sebuah file karena alasan luar,ini akan mengembalikan nil,ditambah sebuah string dengan pesan kesalahan. Disini,kamu punya kesempatan untuk menangani situasi dalam jalur yang tidak umum,sebagai contoh dengan menanyakan user untuk nama file yang lain:

local file, msg repeat

print "enter a file name:" local name = io.read()

if not name then return end -- no input file, msg = io.open(name, "r")

if not file then print(msg) end until file

Jika kamu tidak ingin menangani situasi ini,tetapi ingin bermain aman,kamu cukup gunakan

assert untuk menjaga operasi tersebut:

file = assert(io.open(name, "r"))

Ini adalah gaya Lua;Jika io.open gagal,assert akan menampilkan sebuah error:

file = assert(io.open("no-file", "r"))

--> stdin:1: no-file: No such file or directory

Pemberitahuan bagaimana pesan kesalahan,hasil kedua dari io.open,menjadi argument kedua di assert.