実践Common lispを読み始めた-第19章 例外処理を超えて:コンディションと再起動(1)

handler-caseとhandler-bind

try{
    hogehoge...
}catch(Exception e){
    yogeyoge...
}

(handler-case (hogehoge ...)
  (exception (e) (yogeyoge ...)))

に相当する。
一方のhandler-bindは特定の例外処理を決めるのだけど、処理した後さらに上位のハンドラに通知する。

(handler-bind ((exception (e) #'yogeyoge)
               ...)
           (hogehoge ...))

try{
    hogehoge ...
}catch(Exception e){
    yogeyoge ...
    throw e;
}

と同じか?(自信なし)

実際に動くコードを書いてみる。

CL-USER> (define-condition invalid-argument-exception (error)
	   ((message :initarg :message :reader message)
	    (value :initarg :value :reader value)))
INVALID-ARGUMENT-EXCEPTION
CL-USER> (defun level1 (arg)
	   (handler-case
	       (level2 arg) 
	     (invalid-argument-exception (err)
	       (format t "Invalid argument in level2"))))
LEVEL1
CL-USER> (defun level2 (arg)
	   (handler-bind
	       ((invalid-argument-exception #'(lambda (err)
						(format t "level2: InvalidArgumentException: ~a~%" (value err)))))
	     (level3 arg)))
LEVEL2
CL-USER> (defun level3 (arg)
	   (error 'invalid-argument-exception :message "InvalidArgumentException" :value arg)) ;;level3は必ずエラーを投げる
LEVEL3
CL-USER> (level3 10)
; Evaluation aborted  ;;予定通り
CL-USER> (level2 10)
level2: InvalidArgumentException: 10
; Evaluation aborted  ;;handler-bindだけなので、例外処理された後toplevelに例外が投げられてデバッガに制御が移る。
CL-USER> (level1 10)
level2: InvalidArgumentException: 10
Invalid argument in level2
NIL ;;level1ではhandler-caseを書いているのでデバッガに制御はいかない。
CL-USER> 

handler-caseとhandler-bindだけだと他の言語の例外とそれほど差がないなー。