Perlの例外が5.14以降で変わった話

詳しくは、このページを見て、”例外処理”で検索するのがいいと思います。
perldelta – perl v5.14.0 での変更点 – perldoc.jp

でも、読んでも分からないので、手を動かしてみます。

Hokkaido.pm Casual#16では、Perl 5.12とPerl 5.16を切り替えながら、
Try::Liteのv0.0.2を使って実演したのですが、
新しく出たTry::Liteのv0.0.3では例の問題を吸収してくれているので、
積極的に使っていきたい所存です。

それはそうと、まずPerlで例外処理の復習から。

use strict;
use warnings;

my $a = 0;
my $b;
eval {
    $b = print 2 / $a;
};

if ( $@ ) {
    print "oops!\n$@";
}
else {
    print $b, "\n";
}

これを実行すると、こんな感じ。
$ perl aaa.pl
oops!
Illegal division by zero at aaa.pl line 7.

見ての通り、0で割ってる訳ですが、
もし、eval{...};で括らないと、例外が起きて実行が中断されます。

では、eval{...};を取り除いてみます。

use strict;
use warnings;

my $a = 0;
my $b = print 2 / $a;

print "here!\n";
print $b, "\n";

こんな感じですね。
$ perl bbb.pl
Illegal division by zero at bbb.pl line 5.

残念ながら、5行目で中断されてしまいました。
そこで、最初に紹介したコードでは、
例外が発生する可能性のある部分をeval{...};で括ってあげて、
例外が起きてれば、その旨が入っているであろう$@をチェックして、
例外が起きた場合は、その旨を表示してた訳です。

で、やっとタイトルの件です。
まずは、こんな感じのコードを用意します。

use strict;
use warnings;

my $e = '';
eval {
    local $@;
    eval {
        die 'oops!';
    };

    $e = $@;
    die $@;
};

if ( $@ ) {
    print "\$@ = $@";
}

if ( $e ) {
    print "\$e = $e";
}

自分の場合はperlbrewを使っているので、こんな感じで実行します。
$ perlbrew switch-off
perlbrew is switched off.
$ perl ccc.pl
$e = oops! at ccc.pl line 8.

手元の環境だと、Perlは5.12.3でした。

次に、いつも使ってるPerlに戻します。
$ perlbrew switch perl-5.16
$ perl ccc.pl
$@ = oops! at ccc.pl line 8.
$e = oops! at ccc.pl line 8.

という訳で、local $@;することで、
$@を上書きされたくないケースでもあるのかなーって思いつつも、
localよく分かってないし、そういうケースに遭遇したことないので、
Perlのバージョンでこういう差異があることがあるよ!程度に覚えておこうと思います。

おしまい。

Leave a Comment