Senin, 07 Desember 2009

Variabel state di Perl 5.10

Bahasa Perl termasuk memberi banyak pilihan skop variabel bagi programer. Pertama, ada variabel global (tepatnya variabel package, karena sebetulnya tidak ada variabel global di Perl; ck ck ck di awal artikel sudah berbohong? :-)

Kedua, yang mungkin paling sering kita pakai, variabel leksikal alias variabel privat yang dideklarasikan dengan my() yang hanya bisa dilihat/diakses oleh blok atau file atau eval tempat si variabel dideklarasi.

Ketiga, variabel lokal untuk dynamic scoping, menggunakan kata kunci local(), biasanya kita pakai untuk menyimpan/mem-backup sebuah variabel, lalu mengubahnya di dalam sebuah blok, dan nanti otomatis saat kita keluar dari blok tersebut nilai si variabel akan terpulihkan kembali. Kita bisa melokalkan variabel package, filehandle, glob, dsb. Bahkan kita bisa melakukan hal seperti ini:

$config = { foo=>'ujan', bar=>'kemarau' };
...
{
local $config->{foo} = 'blah';
sini();
sana();
}
print $config->{foo}; # 'ujan' lagi


Pada contoh di atas, kita melokalkan satu pair dari hash saja. Saat masuk ke sini() dan sana(), nilai lokal $config->{foo} akan terus dipertahankan. Inilah yang dimaksud dynamic scoping, jadi tidak berbasis pada source code melainkan pada alur running program. Setelah blok selesai, barulah nilai lama $config->{foo} pulih. Asyik kan?

Keempat, ada lagi yang namanya our(), mulai diperkenalkan sejak Perl 5.6. Ini pada dasarnya adalah pengganti untuk "use vars qw($foo)". our() membuat alias leksikal untuk sebuah variabel global, eh, variabel package. Tentu saja variabel tersebut nanti bisa diakses dari package lain.

Kelima, yang menjadi topik posting blog ini, yaitu variabel state. Variabel ini diperkenalkan sejak Perl 5.9.sekian dan resmi menjadi bagian fitur baru dari 5.10. Untuk menggunakannya, di awal skrip kita harus melakukan:

use feature 'state';

atau:

use feature ':5.10'; # jangan lupa kutipnya ya...

Kegunaan variabel state adalah untuk membuat variabel leksikal yang persisten. Sebelumnya hal ini memang bisa dilakukan menggunakan closure, tapi terus terang saya malas menghafalnya. Setelah ada state(), barulah jadi lebih termotivasi untuk menggunakan leksikal persisten.

Akhir-akhir ini saya sering membuat metode yang mengembalikan nilai konstan/statik, contohnya:

sub config_vars {
[qw/
recurse_hash
recurse_array
parse_prefix
...
/]
}


Kenapa tidak pakai variabel biasa saja (mis menggunakan our())? Tujuannya sih agar bisa memanfaatkan inheritance.

Tapi, tahukah Anda, bahwa setiap kali dipanggil, si metode tersebut akan membuat arrayref baru? Buktinya:

$ perl -le'sub f { [1,2,3,4,5,6,7,8,9,10] } print f for 1..5'
ARRAY(0x9d1c40)
ARRAY(0xa083c8)
ARRAY(0xa083b0)
ARRAY(0xa08398)
ARRAY(0xa08380)


Pemborosan bukan? Nah, solusinya kita bisa menggunakan variabel state:

sub config_vars {
state $a = [qw/
recurse_hash
recurse_array
parse_prefix
...
/];
}


Variabel $a ini akan hidup terus walaupun sudah keluar dari skop (tentu saja, pada ujungnya nanti akan di-garbage collect kalau memang tidak ada yang memakai lagi).

Kini:

$ perl -lE'sub f { state $f = [1,2,3,4,5,6,7,8,9,10] } print f for 1..5'
ARRAY(0x12ffc40)
ARRAY(0x12ffc40)
ARRAY(0x12ffc40)
ARRAY(0x12ffc40)
ARRAY(0x12ffc40)


Oya, -E sama seperti -e tapi menghidupkan semua fitur Perl terbaru (dalam kasus ini, ekivalen dengan "use feature ':5.10'").

Selamat bermain dengan variabel di Perl!

Tidak ada komentar:

Posting Komentar

Catatan: Hanya anggota dari blog ini yang dapat mengirim komentar.