これはMoritz Lenz氏のWebサイトPerlgeek.deで公開されているブログ記事"Perl 5 to 6" Lesson 26 - Exceptions and control exceptionsの日本語訳です。
原文はCreative Commons Attribution 3.0 Germanyに基づいて公開されています。
本エントリにはCreative Commons Attribution 3.0 Unportedを適用します。
Original text: Copyright© 2008-2010 Moritz Lenz
Japanese translation: Copyright© 2011 SATOH Koichi
NAME
"Perl 5 to 6" Lesson 26 - 例外と制御例外
SYNOPSIS
try {
die "OH NOEZ";
CATCH {
say "there was an error: $!";
}
}
DESCRIPTION
例外はその名前に反してまったく例外的なものではありません。実際のところPerl6では通常の制御フローの一部です。
例外は潜在的なエラー(例えば0除算、存在しないメソッドの呼び出し、型チェック失敗)またはdie
その他の関数の明示的な呼び出しによって生成されます。
例外が投げられるとプログラムは呼び出しフレームからCATCH
ブロックかtry
ブロックを探し、スタックを完全に巻き戻します(つまりそれまでに呼び出された全部のサブルーチンから無理矢理戻ってくるということです)。
もしCATCH
もtry
も見つからなければプログラムは終了し、運が良ければ役に立つエラーメッセージが表示されます。
どちらか一方が見つかった場合はエラーメッセージは特殊変数$!
に格納され、CATCH
ブロックが実行されます(try
ブロックにCATCH
ブロックがない場合、ブロックはundef
を返します)。
ここまでの説明ではまだ例外が例外的なものに思えるかも知れませんが、エラー処理は些末なアプリケーションでもなければ不可欠です。
ただそればかりでなく、通常のreturn
文も例外を投げているのです!
これは制御例外と呼ばれ、CONTROL
ブロックで捕捉することができ、そうしない場合はサブルーチン宣言で暗黙的に捕捉されます。
次の例を考えてみて下さい:
use v6;
my $block = -> { return "block"; say "still here" };
sub s {
$block.();
return "sub";
}
say s();
return "block"
が制御例外を投げ、現在のブロックから抜ける(したがってstill here
は表示されない)のみならず、サブルーチンからも抜けます。これはsub s...
宣言で捕捉されます。
ペイロード——この例では文字列——は戻り値として渡され、最後の行のsay
がこれを表示します。
$block.()
をtry { ... }
ブロックの中に入れたりCONTROL { ... }
ブロックをサブルーチンの本体に置いたりすることで例外を捕捉できます。
他のプログラミング言語とは逆にCATCH
/CONTROL
ブロックはエラーが捕捉されるスコープの(外ではなく)中にあり、字句的変数への完全なアクセスが与えられています。このことは役に立つエラーメッセージを作るのを容易にし、またエラーが処理される前にDESTROY
ブロックが実行されることを防ぎます。
投げられない例外
Perl6はマルチスレッドの、特に自動並列化の考えを取り入れています。 1スレッドの終了が全スレッドに影響することがないように、「ソフトな」例外が考案されました。
関数がfail($obj)
を呼ぶと特別な未定義値を返します。これはペイロードに$obj
(大抵の場合はエラーメッセージ)とバックトレース(ファイル名と行番号)を格納しています。
この特殊な未定義値を確認なしに処理しようとすると通常の例外が投げられます。
my @files = </etc/passwd /etc/shadow nonexisting>;
my @handles = hyper map { open($_) }, @files;
この例のhyper
演算子はmap
に可能な限り動作を並列化するよう伝えます。
nonexisting
ファイルのオープンに失敗した場合、通常のdie "No such file or directory"
では他のファイルオープン処理も中断してしまいます。
しかし失敗したオープン処理は代わりにfail("No such file or directory")
を呼ぶので、呼び出し元は@handles
の内容を確認することができ、完全なエラーメッセージにもアクセスできます。
ソフトな例外が気に入らない場合、プログラムの最初にuse fatal;
と書くとfail()
から生じる例外が即座に投げられるようになります。
MOTIVATION
良いプログラミング言語にはエラー状態を扱うための例外が必要です。 成功したかどうか戻り値をいつも確認することは厄介だし忘れがちです。
伝統的な例外は暗黙の並列化にとっては有害なことがあるので、両者の最上の部分を組み合わせる解法が必要でした: 一度にすべてを殺してしまわず、またどんな情報も取りこぼしてしまわない方法がです。
コメント
コメントを投稿