英語圏ではかなり前から die && $@ で開発し続けることのリスクについて語られていたが、いよいよ具体的な弊害が出て来ているようなので、かいつまんで LT 。日本でもそう遠くない未来だと思う。
eval {
die '50 msec!';
};
if ($@ && $@ =~ /^50 msec!/) {
say 'FreeeeeeeeeeeeeeeeeeakOut!';
}
アプリケーションの規模が大きくなってくると、単純な文字列をみて例外処理をするのがめんどくさくなってきます。 実は die の引き数はどんな値でも渡せて、 $@ はどんな物でも入ります。 普通の変数と一緒なのです。
という事は例外を処理するクラスを作って、例外を受けた時に処理すると捗るはず!
use strict;use warnings;use 5.014;
package Exception {
sub throw {
my($class, $message) = @_;
die bless \$message, $class;
};
sub message { ${ $_[0] } . ' or die!' }
};
eval {
Exception->throw('10msec');
};
say $@->message if $@;
Exception::Class ってのが有名ですが、ソースコードよむのたいへん。。。
そこで作った!おれ!カジュアルに!もじゅーる!たいにー! ソースコードレベルで、初心者の人でも何やってるかわかるように書いてるから安心安全。
使い方は、良くあるやつと同じ感じですね!
package MyException;
use parent 'Exception::Tiny';
package main;
# try
eval {
MyException->throw( 'oops!' ); # same MyException->throw( message => 'oops!' );
};
基本的には IO Error とか Network Error とか、エラーの種類に応じたクラスを作って行って、エラーの種類は $@ の中身を見て判断する事になります。 一般的な言語では
try {
} catch (IOError e) {
} catch (50MSecError e) {
}
などのように簡単に処理出来るけど(実はPerlでもできるが後述)、 Perl っぽくかくのを支援室する形で caught てメソッドあります。
if (my $e = $@) {
if (MyException->caught($e)) {
} elsif (OrDieException->caught($e)) {
}
}
Q. throwf($format, ...) みたいな pull-req 採用してほしい A. Exception::Tiny では、本当に必要な機能だけしかもたずに、ユーザの細かいニーズは Exception::Tiny を継承したユーザ側の基礎の例外クラスで実装してほしいと思っています。 なので、 @Your::Proj::ISA = 'Exception::Tiny' してる Your::Proj の中に便利メソッドをいっぱい早して捗って下さい。あくまでも例外クラス作成のお手伝いだけをするのです。
例外処理クラスを作って処理すると、例外出したり例外のハンドリングが楽になります。
CPAN には try catch を処理するモジュールもいっぱいありますね。
try {
die Some::Class->new(code => 404 );
} catch (Some::Class $e) {
}
みたいにモダンに書ける。。。!しかし依存関係をみると、、Moose, B::Hooks::EndOfScop, Devel::Declare, お、、、おう。。。カジュアルじゃない。。。!
try {
die "foo";
} catch {
warn "caught error: $_"; # not $@
};
わりとシンプル!一般的に良くつかわれてる。
「特に受け取りたくない種類の例外だったら、宣言しなくても勝手に rethrow してほしい、 auto rethrow しないと例外キャッチするだけして処理しなくてバグるし、だるいめんどい、オフィス暑い〜○い〜もうおれはだめだ〜」みたいなこといってたので、丁度 exception 期の僕はカジュアルにモジュール作ったんですね。
以外と $@ の扱いは難しくて面倒なのです。
例外処理中に例外発生したら?
例外発生した直後に DESTROY のなかで eval してるオブジェクトがあったら?
こういうまとめもあったけど、とにかく面倒ごとを良い感じにやるソリューションを素直に使ったほうがいいです。try-catch系モジュールは $@ をうまい具合に保存して元に戻してくれるって安心設計になっていて面倒ごとを隠蔽します。
ついに顕在化し始めた exception 処理に対するリスクヘッジソリューションとして Exception::Tiny と Try::Lite の紹介をしました。
Use a spacebar or arrow keys to navigate