• Tidak ada hasil yang ditemukan

Menangani Exception (Exception Handling)

Dalam dokumen Buku bhs pemrograman Q Equational 2018 (Halaman 119-124)

10 fungsi Built-In

10.7 Menangani Exception (Exception Handling)

Seperti yang telah disebutkan, bahasa Q hanya mengetahui beberapa kondisi runtime error

“yang keras” a.k.a. exception seperti tumpukan/stack atau memory overflow. Bagaimanapun,

exception “yang lembut” dapat juga dihasilkan dan ditangani di dalam cara manapun yang

diinginkan. Fungsi berikut digunakan untuk berhadapan dengan bermacam-macam exception selama evaluasi ungkapan:

halt penghentian evaluasi

quit keluar interpreter Q

catch F X menangani suatu exception

throw X menimbulkan suatu exception

trap ACT SIG menjerat signals/isyarat

Fungsi halt tidak pernah mengembalikan suatu hasil, tetapi menimbulkan suatu exception yang secara normal menyebabkan proses evaluasi menjadi digugurkan dengan seketika. Ini tempat peristirahatan akhir yang biasanya digunakan dalam hal suatu kondisi kesalahan fatal. Fungsi quit itu seperti halt, tetapi juga menyebabkan keluar dari interpreter dan mengembalikanmu kepada shell sistem operasi; operasi ini sering digunakan secara interaktip untuk mengakhiri suatu sesi dengan interpreter. (Catat bahwa di dalam suatu script multithreaded, lihat Bagian 12.12 [POSIX Threads], halaman 169, quit hanya mengakhiri program ketika dilibatkan dari thread utama. Di dalam threads lain hanya bertindak seperti halt.)

Jika flag break terpasang (lihat Catatan tambahan D [Debugging], halaman 229), fungsi break menyela suatu evaluasi dan memohon debugger simbolis membangun ke dalam interpreter Q, sama halnya jika pemakai mengetik Ctl-C. Operasi ini mengijinkan kamu untuk menetapkan breakpoints di dalam suatu script.

Sebagai contoh,

foo X = break || bar X;

menyebabkan debugger menjadi dilibatkan secepat aturan dieksekusi. Jika flag break batal maka operasi ini tidak mempunyai efek. Setidak-Tidaknya, fungsi break mengembalikan (). Fungsi gagal digunakan untuk menggugurkan aturan yang sekarang, hanya seperti suatu failing qualifier. Perbedaannya adalah yang gagal dapat digunakan di manapun di dalam sisi right-hand atau qualifier dari suatu aturan, dan menyebabkan aturan dikeluarkan dengan seketika. Ini mengijinkan kamu untuk menangani kondisi-kondisi kesalahan/error yang rumit yang terjadi selama suatu aturan telah sedang dieksekusi, dan juga menyediakan suatu metoda efisien untuk menerapkan algoritma backtracking. Sebagai contoh, di sini adalah suatu solusi cepat untuk

masalah “N queens” yang terkenal:

queens N = search N 1 1 [];

search N I J P = write P || writes "\n" if I>N;

= search N (I+1) 1 (P++[(I,J)]) || fail if safe (I,J) P;

= search N I (J+1) P if J<N; = () otherwise;

safe (I1,J1) P = not any (check (I1,J1)) P; check (I1,J1) (I2,J2)

= (I1=I2) or else (J1=J2) or else (I1+J1=I2+J2) or else (I1-J1=I2-J2);

Algoritma ini mencetak ke luar semua penempatan yang valid (yaitu, daftar pasangan (row,column)) dari N queens pada suatu N times N board. Catatlah penggunaan yang gagal di dalam penyamaan yang kedua untuk fungsi pencarian, yang menyebabkan aturan gagal setelah penempatan yang sekarang telah dicoba, setelah evaluasi yang meneruskan aturan yang ketiga yang menempatkan queen ke dalam kolom yang berikutnya.

Hal ini memutar definisi ke dalam suatu algoritma backtracking. Fungsi yang aman memverifikasi bahwa suatu penempatan (I1,J1) tidak meletakkan queen di bawah pengendalian dengan ratu lain manapun yang telah ditempatkan.

Fungsi catch mengijinkan kamu untuk menangani kedua “exception yang sulit (hard exceptions)”yang ditimbulkan ketika interpreter menghadapi satu runtime error conditions yang dibahas di Bagian 7.11 [Menangani Kesalahan/Error], halaman 70, dan “soft exceptions” yang

ditimbulkan oleh fungsi halt dan quit yang telah diterangkan di atas, dan fungsi throw yang dibahas di bawah. Lebih dari itu, interpreter juga menangani signals/isyarat tertentu yang dikirim ke dalamnya, e.g., via/lewat sistem panggilan kill(2), dengan meningkatkan exception yang sesuai. Di dalam implementasi yang sekarang, dengan default hanya signals/isyarat

SIGINT (“break”), SIGTERM (“terminate”) dan SIGHUP (“hangup”) ditangani; dua selanjutnya diperlakukan sebagai permintaan penghentian (termination requests), seperti suatu panggilan kepada fungsi quit. Penangan signals/isyarat (Signal handlers) dapat juga diinstall oleh running script menggunakan fungsi trap yang dibahas di bawah.

Kedua argument catch adalah spesial. fungsi catch pertama mengevaluasi argument kedua nya, ungkapan target dan, jika semua baik-baik, mengembalikan nilai ungkapan itu .

Cara lainnya, bila ada exception diangkat sepanjang evaluasi dari ungkapan target, itu mengevaluasi argument yang pertama (Penangan Exception), menerapkannya kepada nilai dari exception, dan mengembalikan hasil yang dihitung oleh penangan exception (Exception handler).

Di dalam kasus suatu kondisi runtime error dan exceptions diangkat dengan fungsi halt dan quit, nilai exception dari format syserr N di mana N adalah satu dari kode kesalahan/error bilangan bulat/integer didaftarkan di bawah:

1: Break: break signal, user typed Ctl-C.

2: Halt: invokation menyangkut fungsi halt (penghentian), atau meminta untuk mengevaluasi halt dari debugger.

3: Quit: isyarat penghentian (termination signal), invokation menyangkut fungsi quit (Berhenti/meninggalkan), atau meminta untuk mengeluarkan (exit) interpreter dari debugger. 4: Memory overflow (Memori meluap): usaha untuk mengalokasikan memori untuk tumpukan/stack atau suatu ungkapan baru pada tumpukan gagal (the heap fails).

5, 6: Stack overflow (Tumpukan meluap): usaha untuk mendorong (push) suatu ungkapan pada stack/tumpukan, atau pengaktifan dari suatu aturan gagal karena batas ukuran stack telah dicapai (lihat komentar pada manajemen memori di Bagian B.1 [Menjalankan Interpreter dan Compiler], halaman 199). 5 isyarat suatu tumpukan ungkapan overflow/meluap, 6 suatu overflow menyangkut tumpukan aturan.

7: Symbol table overflow: usaha untuk menciptakan suatu simbol variabel baru gagal.

8: Conditional error (Kesalahan bersyarat): kondisi persyaratan dari suatu aturan tidak mengevaluasi kepada suatu nilai kebenaran.

9: External function error (Kesalahan fungsi eksternal): suatu fungsi eksternal (lihat Catatan tambahan C [Penghubung Bahasa C], halaman 217) mengisyaratkan suatu kondisi error/kesalahan.

Mari mencoba ini dengan memaksa suatu kondisi tumpukan/stack overflow:

==> iter 100000000 (+) 1 ! Stack overflow

>>> iter 100000000 (+) 1

==> catch exception (iter 100000000 (+) 1) exception (syserr 5)

Constructor/pembangun Syserr kepunyaan type SysException Built-In, yang pada gilirannya adalah suatu subtype exception. Type ini mungkin adalah pemikiran sebagai hal yang sudah dikenal sebagai berikut:

public type Exception;

public type SysException : Exception = const syserr N;

Exception User-defined dapat dihasilkan dengan throw. Fungsi throw menaikkan suatu exception yang nilainya diberikan oleh argument tunggal nya (tidak khusus). Sebagai contoh:

hd [] = throw ’(hd []);

exception X = writes "Exception: " || write X || writes "\n";

Dengan definisi ini kita mempunyai:

==> catch exception (hd [1..3]) 1 ==> catch exception (hd [1..0]) Exception: ’(hd []) () ==> hd [1..0] ! Exception ’(hd []) >>> hd [1..0] ^

Catat bahwa jika suatu exception diangkat dengan throw adalah tidak ditangani dengan suatu catch yang bersesuaian, kemudian interpreter menggugurkan evaluasi dan mencetak suatu pesan kesalahan (dan akan juga memohon debugger untuk melaporkan aturan yang menghasilkan exception, jika break terpasang).

Fungsi catch dan throw dapat juga digunakan untuk menerapkan kembalian nilai tidak lokal. Sebagai contoh, di sini adalah suatu variasi menyangkut fungsi queen N yang mengembalikan solusi yang pertama secepat [itu] telah ditemukan selama mundur/menarik kembali (backtracking):

queens1 N = catch id (search1 N 1 1 []); search1 N I J P = throw P if I>N;

= search1 N (I+1) 1 (P++[(I,J)]) || fail if safe (I,J) P; = search1 N I (J+1) P if J<N;

= () otherwise;

Di sini, “penangan exception (exception handler)” hanya fungsi identitas id, seperti digambarkan oleh standard library, lihat Bagian 11.1 [Fungsi Standard], halaman 115.

Trik programming rapi yang lain adalah berikutnya yang membuat aturan gagal jika suatu exception terjadi selama evaluasi dari sisi right-hand:

foo X = catch fail (bar X);

Hal ini bekerja karena argument handler, yang khusus, dievaluasi hanya jika suatu exception benar-benar ditemui selama evaluasi dari ungkapan target. Cara lainnya, foo X akan hanya mengembalikan nilai bar X.

Para programmer Lisp dan C++ akan mungkin kehilangan suatu parameter tambahan yang membatasi macam-macam exception ditangani dengan catch. Kamu dapat menerapkan ini dengan mudah sendiri dengan memeriksa nilai exception di dalam fungsi handler mu, dan

“throw on” suatu exception yang tak dikenal ke catch yang memasukkan berikutnya (next enclosing catch):

type MyException : Exception = const empty_list; hd [] = throw empty_list;

myexception X:MyException

= writes "myexception: " || write X || writes "\n" || halt;

myexception X = throw X otherwise;

Catat bagaimana kita menerapkan exception empty_list menggunakan Subtype exception kita sendiri Myexception. Metoda ini dalam structuring exception error/kesalahan direkomendasikan karena [itu] membuatnya lebih mudah untuk menyoroti sumber dari suatu exception. [Itu] juga memungkinkan kita untuk menggunakan suatu type guard (cf. Bab 8 [Types], halaman 73) dalam rangka melihat kemungkinan type exception yang spesifik, bukannya mempunyai untuk membeda-bedakan pola exception yang berbeda.

Akhirnya, fungsi trap mengijinkan kamu untuk mempunyai exception yang dihasilkan ketika suatu signal tiba. Fungsi trap mengambil dua argument, ACT dan SIG, menandakan tindakan untuk dilakukan dan banyaknya signal/isyarat untuk di-trap. [Itu] mengembalikan tindakan yang sebelumnya dihubungkan dengan signal/isyarat. ACT harus suatu nilai integer/bilangan bulat. Jika positif maka signal/isyarat menaikkan suatu exception dari format syserr (-SIG); jika negatif maka isyarat dengan sepenuhnya diabaikan; dan jika nol maka interpreter berbalik ke penanganan default signal/isyarat itu.

Kamu dapat juga menggunakan trap untuk menggambarkan kembali penanganan default menyangkut break dan termination signal.

Untuk mengijinkan signals/isyarat untuk ditangkap secara terpercaya, signals/isyarat menjadi

“di-block/dihalangi” (yaitu, mereka di-queued/antri untuk pengiriman selnjutnya) selama catch mengevaluasi suatu penangan exception (exception handler). Sebagai contoh, di sini adalah suatu script kecil yang menetapkan beberapa penangan signals dan menjaga dalam mencetak signals yang terjerat sampai dapat diakhiri dengan kill - 9 atau waktu tunggu fungsi sleep berakhir.

(Fungsi sleep diuraikan di bawah. Signal/isyarat simbolis fungsi constants dan getpid dan printf disajikan oleh modul clib, lihat Bab 12 [Clib], halaman 141.)

test = do (trap 1) [SIGINT,SIGTSTP,SIGTERM,SIGHUP,SIGQUIT] || printf "I’m running as pid %d, try to kill me!\n" getpid || loop;

loop = flush || catch sig (sleep 100);

sig (syserr K) = printf "Hey, I got signal %d.\n" (-K) || loop;

Dalam dokumen Buku bhs pemrograman Q Equational 2018 (Halaman 119-124)