北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

dieの引数とか例外の伝搬とかPROPAGATEとか

dieの引数って文字列だけじゃなかったんですね。

こんな風にdieの引数省略したら、見慣れないメッセージが。

% perl
eval {die "in eval"; };
die;
in eval at - line 1.
        ...propagated at - line 2.

perldocを見てみます。

If LIST is empty and $@ contains an object reference that has a PROPAGATE method, that method will be called with additional file and line number parameters. The return value replaces the value in $@. i.e. as if $@ = eval { $@->PROPAGATE(__FILE__, __LINE__) }; were called.

If $@ is empty then the string "Died" is used.

perlfunc

へえ。dieの引数って省略できたんですね。しかも、PROPAGATEなんてメソッドも知りませんでした。

die() can also be called with a reference argument. If this happens to be trapped within an eval(), $@ contains the reference.

perlfunc

しかも、dieにリファレンス渡せるなんて。

試しにコード書いてみました。

use strict;
use warnings;

{
	package MyException;
	sub new{ bless \ $_[1], $_[0]; }
	sub PROPAGATE{
		my $self = shift;
		my ($file, $lineno) = @_;
		return MyException->new(
			sprintf('propagated(%s/%d):%s', $file, $lineno, $$self),
		);
	}
}

eval{
	eval {
		eval{
			die MyException->new("first error");
		};
		print ${$@}, "\n";
		die;
	};
	print ${$@}, "\n";
	die;
};
print ${$@}, "\n";
die;

実行結果は以下。

first error
propagated(test.pl/22):first error
propagated(test.pl/25):propagated(test.pl/22):first error
MyException=SCALAR(0x800e34)

うーん、まあ、意図した通りの動きなんですけど、PROPAGATEの使い道がちょっと思いつかないですね。Java脳だと、単純に$@を別の例外でラップしたくなります。