home ホーム search 検索 -  login ログイン  | reload edit datainfo version cmd icon diff delete  | help ヘルプ

Perl/codepiece/try-catch-exception01

Perl/codepiece/try-catch-exception01

Perl / codepiece / try-catch-exception01
id: 116 所有者: msakamoto-sf    作成日: 2007-03-14 22:47:19
カテゴリ: Perl 

Perl(正確にはPerl5.X系列まで)にはtry-catch構文は存在しない。しかし、evalやcoderefを引数にとることができるなどの特徴を用い、幾つかの疑似try-catch的テクニックは存在する。Error.pmとうモジュールも公開されており、こちらを活用するとOOP的なtry-catchを実現できる。

参考ページ:

eval{}中のdieを$@で判別する基本形

eval{}コードブロック中でのdieは、コードを抜けた後、 $@ 変数で参照できる。これを利用して、以下のような疑似try-catch機能を利用できる。

eval {
    # do-something
    if ( exception-condition ) {
        die "exception message";
    }
};
if ($@) {
    &someErrorHandler($@);
}

これが、perl.comにも載っているし、自分自身、恐らくどこかしかで目にしたのだろう、いつの間にかおぼえていた疑似コードである。(ひょっとしたらperl.comで目にした記憶が時間軸を前後したのかも知れない。)

これについてはわざわざコードピースを示すまでもない。

Error.pmの使用例

perl.comでも掲載されている、Perlでtry-catch, そしてOOPな例外処理機構を使用するのにお奨めのモジュール、それがError.pmらしい。perl.comに掲載されている記事やCPANのPODを元に、簡単なコードピースで実験をしてみる。

  • コードピース:スクリプトの引数に応じて発生させるErrorオブジェクトを変化させ、独自Errorや基本的なErrorを発生させてみる。
#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;
use Error qw(:try);
use Switch;

my $d = shift || 0;
my $a = -1;

try {
	switch($d) {
		case -2 {
			# Error::Simpleをそのままthrowしてみる。
			throw Error::Simple("d = -2");
		}
		case -1 {
			# 元になるErrorオブジェクトを直にthrowしてみる。
			throw Error(-text => "d = -1");
		}
		case 0 {
			# Error::Simpleをシンプルに継承したものをthrowしてみる。
			throw Error::TestException("d = 0");
		}
		# 以下はErrorを元にした独自Error
		case 1 {
			throw Test1HogeException("d = 1");
			}
		case 2 {
			throw Test2HogeException("d = 2");
			}
		else {
			throw HogeException("d = else");
		}
	}
	$a = $d;
} catch HogeException with {
	my $e = shift;
	print "======== Hoge Exception ========\n";
	print Dumper($e), "\n";
} catch Error with {
	my $e = shift;
	print "e = $e\n";
	print Dumper($e), "\n";
	print "========warn======\n";
	warn $e->text;
} finally {
	print "\n======= last a = [$a]\n";
};

package BoheException;
use base qw(Error);

package HogeException;
use base qw(Error);
use overload ('""' => 'stringify');

sub new {
	my $self = shift;
	my $text = "".shift;
	my @args = ();
	local $Error::Depth = $Error::Depth + 1;
	local $Error::Debug = 1;
	$self->SUPER::new(-text => $text, @args);
}

package Test1HogeException;
use base qw(HogeException);

package Test2HogeException;
use base qw(HogeException);

package Error::TestException;
use base qw(Error::Simple);

引数に応じて何パターンか試してみる。

  • 引数 = -2
e = d = -2 at ./try03.pl line 15.

$VAR1 = bless( {
                 '-file' => './try03.pl',
                 '-text' => 'd = -2',
                 '-line' => 15,
                 '-package' => 'main'
               }, 'Error::Simple' );

========warn======
d = -2 at ./try03.pl line 43.

======= last a = [-1]
  • 引数 = -1
e = d = -1
$VAR1 = bless( {
                 '-file' => './try03.pl',
                 '-text' => 'd = -1',
                 '-line' => 18,
                 '-package' => 'main'
               }, 'Error' );

========warn======
d = -1 at ./try03.pl line 43.

======= last a = [-1]
  • 引数 = 0
e = d = 0 at ./try03.pl line 21.

$VAR1 = bless( {
                 '-file' => './try03.pl',
                 '-text' => 'd = 0',
                 '-line' => 21,
                 '-package' => 'main'
               }, 'Error::TestException' );

========warn======
d = 0 at ./try03.pl line 43.

======= last a = [-1]
  • 引数 = 1
======== Hoge Exception ========
$VAR1 = bless( {
                 '-stacktrace' => 'd = 1 at ./try03.pl line 24
',
                 '-file' => './try03.pl',
                 '-text' => 'd = 1',
                 '-line' => 24,
                 '-package' => 'main'
               }, 'Test1HogeException' );


======= last a = [-1]
  • 引数 = 2
======== Hoge Exception ========
$VAR1 = bless( {
                 '-stacktrace' => 'd = 2 at ./try03.pl line 27
',
                 '-file' => './try03.pl',
                 '-text' => 'd = 2',
                 '-line' => 27,
                 '-package' => 'main'
               }, 'Test2HogeException' );


======= last a = [-1]
  • 引数 = 3
======== Hoge Exception ========
$VAR1 = bless( {
                 '-stacktrace' => 'd = else at ./try03.pl line 30
',
                 '-file' => './try03.pl',
                 '-text' => 'd = else',
                 '-line' => 30,
                 '-package' => 'main'
               }, 'HogeException' );


======= last a = [-1]

細かい解説は見れば自明なので省略するが、とりあえず独自のErrorクラスを構築し、Javaなどと同じ使い心地で使用できるのを確認できた。

try{}中で直接 warn, die を使ってみる。

上記例はあくまでも教科書通りに、Errorオブジェクトをthrowしている。では実際に、try {} 中で die や warn が発生するとどうなるかを確認しておく。

  • コードピース
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Error qw(:try);

try {
    warn "warning!!";
    die "die!!";
} catch Error with {
    my $e = shift;
    print "e = $e\n";
    print Dumper($e), "\n";
    print "========warn======\n";
    warn $e->text;
} finally {
    print "\n======= last \n";
};
  • 出力
warning!! at ./try04.pl line 9.
e = die!! at ./try04.pl line 10.

$VAR1 = bless( {
                 '-file' => './try04.pl',
                 '-text' => 'die!!',
                 '-line' => '10',
                 '-package' => 'Error'
               }, 'Error::Simple' );

========warn======
die!! at ./try04.pl line 16.

======= last

die の場合、Error::Simpleにラッピングされてthrowされていることを確認できた。

try{}中で直接 carp, croak を使ってみる。

warn, die と同じ効果になると思われる。

  • コードピース
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Carp;
use Error qw(:try);

try {
    carp "carp!!";
    croak "croak!!";
} catch Error with {
    my $e = shift;
    print "e = $e\n";
    print Dumper($e), "\n";
    print "========warn======\n";
    warn $e->text;
} finally {
    print "\n======= last \n";
};
  • 出力
carp!! at /usr/lib/perl5/site_perl/5.8.5/Error.pm line 428
e = croak!! at /usr/lib/perl5/site_perl/5.8.5/Error.pm line 428.

$VAR1 = bless( {
                 '-file' => '/usr/lib/perl5/site_perl/5.8.5/Error.pm',
                 '-text' => 'croak!!',
                 '-line' => '428',
                 '-package' => 'Error'
               }, 'Error::Simple' );

========warn======
croak!! at ./try04.pl line 19.

======= last

ほぼ予想通りである。Perl/codepiece/carp01では、(carp,croak)と(cluck,confess)系で違いが見られなかった、とあるが、ここでようやく明らかな出力の差異が認められた。上記コードピースのcarp, croakをそれぞれcluck, confessで置き換えた結果を下に示す。

cluck!! at ./try04.pl line 12
        main::__ANON__() called at /usr/lib/perl5/site_perl/5.8.5/Error.pm line 428
        eval {...} called at /usr/lib/perl5/site_perl/5.8.5/Error.pm line 420
        Error::subs::try('CODE(0x816446c)', 'HASH(0x8164448)') called at ./try04.pl line 24
e = confess!! at ./try04.pl line 15
        main::__ANON__() called at /usr/lib/perl5/site_perl/5.8.5/Error.pm line 428
        eval {...} called at /usr/lib/perl5/site_perl/5.8.5/Error.pm line 420
        Error::subs::try('CODE(0x816446c)', 'HASH(0x8164448)') called at ./try04.pl line 24.

$VAR1 = bless( {
                 '-file' => './try04.pl',
                 '-text' => 'confess!! at ./try04.pl line 15
        main::__ANON__() called at /usr/lib/perl5/site_perl/5.8.5/Error.pm line 428
        eval {...} called at /usr/lib/perl5/site_perl/5.8.5/Error.pm line 420
        Error::subs::try(\'CODE(0x816446c)\', \'HASH(0x8164448)\') called',
                 '-line' => '24',
                 '-package' => 'Error'
               }, 'Error::Simple' );

========warn======
confess!! at ./try04.pl line 15
        main::__ANON__() called at /usr/lib/perl5/site_perl/5.8.5/Error.pm line 428
        eval {...} called at /usr/lib/perl5/site_perl/5.8.5/Error.pm line 420
        Error::subs::try('CODE(0x816446c)', 'HASH(0x8164448)') called at ./try04.pl line 21.

======= last

このように、cluck, confessを使用すると、細かいスタックトレースが出力できることが分かった。

結論として Error.pm と Carp 系は共存可能 であることを確認できた。



プレーンテキスト形式でダウンロード
現在のバージョン : 1
更新者: msakamoto-sf
更新日: 2008-12-24 22:51:26
md5:8ce7fbb299805df9a9fc7580c3fddf99
sha1:50dea97ef27807c69c32af6cca4bcf95c741690e
コメント
コメントを投稿するにはログインして下さい。