Your browser doesn't support the features required by impress.js, so you are presented with a simplified version of this presentation.

For the best experience please use the latest Chrome or Safari browser. Firefox 10 (to be released soon) will also handle it.

ついに顕在化しはじめた Exception リスク

Yappo

あらすじ

英語圏ではかなり前から die && $@ で開発し続けることのリスクについて語られていたが、いよいよ具体的な弊害が出て来ているようなので、かいつまんで LT 。日本でもそう遠くない未来だと思う。

simpe die

eval {
    die '50 msec!';
};
if ($@ && $@ =~ /^50 msec!/) {
    say 'FreeeeeeeeeeeeeeeeeeakOut!';
}

exception class

アプリケーションの規模が大きくなってくると、単純な文字列をみて例外処理をするのがめんどくさくなってきます。 実は die の引き数はどんな値でも渡せて、 $@ はどんな物でも入ります。 普通の変数と一緒なのです。

という事は例外を処理するクラスを作って、例外を受けた時に処理すると捗るはず!

exception class sample

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 $@;

CPAN ので作りたい

Exception::Class ってのが有名ですが、ソースコードよむのたいへん。。。

Exception::Tiny

そこで作った!おれ!カジュアルに!もじゅーる!たいにー! ソースコードレベルで、初心者の人でも何やってるかわかるように書いてるから安心安全。

使い方は、良くあるやつと同じ感じですね!

sample

package MyException;
use parent 'Exception::Tiny';
package main;
# try
eval {
    MyException->throw( 'oops!' ); # same MyException->throw( message => 'oops!' );
};

caught

基本的には IO Error とか Network Error とか、エラーの種類に応じたクラスを作って行って、エラーの種類は $@ の中身を見て判断する事になります。 一般的な言語では

try {
} catch (IOError e) {
} catch (50MSecError e) {
}

などのように簡単に処理出来るけど(実はPerlでもできるが後述)、 Perl っぽくかくのを支援室する形で caught てメソッドあります。

sample

if (my $e = $@) {
    if (MyException->caught($e)) {
    } elsif (OrDieException->caught($e)) {
    }
}

FAQ

Q. throwf($format, ...) みたいな pull-req 採用してほしい A. Exception::Tiny では、本当に必要な機能だけしかもたずに、ユーザの細かいニーズは Exception::Tiny を継承したユーザ側の基礎の例外クラスで実装してほしいと思っています。 なので、 @Your::Proj::ISA = 'Exception::Tiny' してる Your::Proj の中に便利メソッドをいっぱい早して捗って下さい。あくまでも例外クラス作成のお手伝いだけをするのです。

ここまでのまとめ

例外処理クラスを作って処理すると、例外出したり例外のハンドリングが楽になります。

出してばっかだけど、受け取りどーすんの!?

はい

CPAN には try catch を処理するモジュールもいっぱいありますね。

TryCatch.pm

try {
    die Some::Class->new(code => 404 );
} catch (Some::Class $e) {
}

みたいにモダンに書ける。。。!しかし依存関係をみると、、Moose, B::Hooks::EndOfScop, Devel::Declare, お、、、おう。。。カジュアルじゃない。。。!

Try::Tiny

try {
    die "foo";
} catch {
    warn "caught error: $_"; # not $@
};

わりとシンプル!一般的に良くつかわれてる。

とある知り合いの映画に出たいハッカーが

「特に受け取りたくない種類の例外だったら、宣言しなくても勝手に rethrow してほしい、 auto rethrow しないと例外キャッチするだけして処理しなくてバグるし、だるいめんどい、オフィス暑い〜○い〜もうおれはだめだ〜」みたいなこといってたので、丁度 exception 期の僕はカジュアルにモジュール作ったんですね。

Try::Lite

readmeみながら解説する

なぜ try catch なモジュールを使うのか?

以外と $@ の扱いは難しくて面倒なのです。

例外処理中に例外発生したら?

例外発生した直後に DESTROY のなかで eval してるオブジェクトがあったら?

こういうまとめもあったけど、とにかく面倒ごとを良い感じにやるソリューションを素直に使ったほうがいいです。try-catch系モジュールは $@ をうまい具合に保存して元に戻してくれるって安心設計になっていて面倒ごとを隠蔽します。

まとめ

ついに顕在化し始めた exception 処理に対するリスクヘッジソリューションとして Exception::Tiny と Try::Lite の紹介をしました。

以上です

Use a spacebar or arrow keys to navigate