Akses Object-Oriented

28.3 Akses Object-Oriented

Langkah kita selanjutnya adalah untuk merubah bentuk (transform) tipe baru milik kita menjadi sebuah objek, jadi kita dapat mengoperasikan pada contoh dengan menggunakan sintaks object-oriented yang biasa, seperti :

a = array.new(1000) print(a:size()) --> 1000 a:set(10, 3.4) print(a:get(10)) --> 3.4

Ingatlah bahwa a : size ( ) bernilai sama dengan a.size (a). oleh karena itu, kita harus menyusun ungkapan a.size untuk mengembalikan fungsi getsize. Mekanisme key di sini adalah methamethod __index. Untuk tabel, metamethod ini dipanggil pada saat Lua tidak dapat menemukan sebuah nilai untuk key yang telah ditentukan. Untuk userdata, metamethod ini dipanggil pada semua akses, karena userdata tidak punya key sama sekali.

Dengan itu kita menjalankan kode sebagai berikut : Dengan itu kita menjalankan kode sebagai berikut :

Pada baris pertama, kita membuat sebuah array hanya untuk mendapatkan metatable, yang kita tugaskan ke metaarray. (Kita tidak dapat mengatur metatable dari sebuah userdata dari Lua, tapi kita bisa mendapatkan metatable-nya tanpa syarat). Lalu kita mengatur metaarray. __index ke metaarray. Saat kita mengevaluasi a.size, Lua tidak dapat menemukan key “size” pada objek a, karena objek tersebut merupakan sebuah userdatum. Oleh karena itu, Lua akan mencoba untuk mendapatkan nilai ini dari bidang __index dari metatable a, yang menyebabkannya menjadi metaarray itu sendiri. Namun, metaarray.size adalah array.size, jadi hasil a.size (a) ada di dalam array.size (a), seperti yang diinginkan.

Tentu saja, kita dapat menulis hal yang sama pad C. Bahkan, kita dapat melakukan yang lebih baik. Sekarang array-array tersebut merupakan objek, dengan operasi mereka sendiri, kita tidak perlu memiliki operasi-operasi tersebut di dalam table array lagi. Satu-satunya fungsi yang library masih harus keluarkan adalah new, untuk membuat array-array baru. Semua operasi lainnya datang hanya sebagai method. Kode C dapat mendaftarkan mereka secara langsung sedemikian.

Operasi getsize, getarray dan setarray tidak dapat dirubah dari pendekatan sebelumnya. Apa yang akan berubah adalah bagaimana kita me-register mereka. Karena itu, kita harus merubah fungsi yang membuka library. Pertama, kita membutuhkan daftar-daftar dua fungsi yang terpisah, satu untuk fungsi biasa (regular) dan satu lagi untuk method :

static const struct luaL_reg arraylib_f [] = { {"new", newarray}, {NULL, NULL}

static const struct luaL_reg arraylib_m [] = { {"set", setarray}, {"get", getarray}, {"size", getsize}, {NULL, NULL}

Versi terbaru dari luaopen_array, fungsi yang membuka library, harus membuat metatable , untuk menugaskannya ke bagian __index-nya sendiri, untuk mendaftarkan semua method di sana, dan untuk membuat dan mengisi tabel array :

int luaopen_array (lua_State *L) { luaL_newmetatable(L, "LuaBook.array");

lua_pushstring(L, "__index"); lua_pushvalue(L, -2); /* pushes the metatable */ lua_settable(L, -3); /* metatable.__index = metatable */

luaL_openlib(L, NULL, arraylib_m, 0); luaL_openlib(L, NULL, arraylib_m, 0);

Di sini kita menggunakan bentuk lain dari luaL_openlib. Pada panggilan pertama, saat kita melewatkan NULL sebagai nama library, luaL_openlib tidak membuat tabel apa pun untuk memuat fungsi, sebagai gantinya, itu berasumsi bahwa tabel kemasannya ada di dalam stack, kebetulan dibawah upvalue. Pada contoh ini, kemasan tabel adalah metatable sendiri, yang mana luaL_openlib akan meletakkan method. Panggilan berikutnya kepada luaL_openlib bekerja secara biasa. Membuat tabel baru dengan nama yang telah ditentukan ( array) dan me-register fungsi yang telah ditentukan di sana (hanya new, pada kasus ini).

Sebagai sentuhan terakhir, kita akan menambahkan metode __tostring ke tipe yang baru, jadi perintah print (a) mencetak array disertai dengan ukuran array dari tengah-tengah array (sebagai contoh, array(1000)). Fungsi tersebut adalah sebagai berikut :

int array2string (lua_State *L) { NumArray *a = checkarray(L); lua_pushfstring(L, "array(%d)", a->size); return 1;

Fungsi lua_pushfstring memformat string dan meninggalkannya pada puncak stack. Kita juga dapat menambah array2string ke dalam daftar arraylib_m, untuk mengisinya di dalam metatable dari objek array.