web-dev-qa-db-ja.com

Try :: Tinyは、Perl 5.14以降での例外処理に推奨されていますか?

Perlコミュニティのコンセンサスはそのようです Try::Tiny は、例外を処理するための推奨される方法です。

Perl 5.14(私が使用しているバージョン) 解決するようですissues with eval that Try::Tinyアドレス。ウィルTry::Tinyまだメリットがありますか?

76
Eugene Yarmash

私の回答は不評ですが、PerlプログラマーがPerlで「例外」と呼ぶものの非常に貧弱な概念を使用しようとするべきではないと私は思います。これらは基本的にサイドチャネルの戻り値です。ただし、例外のアイデアに夢中のままであり、グローバル変数を使用して状態を渡すのが複雑であっても、人々はそれを機能させようと試み続けています。

しかし実際には、人々はdieを使用して失敗を知らせます。参照でdieを実行してエラーオブジェクトを返すことができると言う人もいますが、そのためにdieは必要ありません。オブジェクトがあるので、オブジェクトのすべての力を使用する必要があります。

 sub some_sub {
    ...
    return Result->new( error => 1, description => ... ) if $something_went_wrong;
    return Result->new( error => 0, ... );
    }

 my $result = some_sub( ... );
 if( $result->is_error ) { ... };

これには、グローバル変数、遠くでの行動、スコーピングの頭痛、特別な特別措置は必要ありません。小さなクラスResultまたはそれを呼び出したいものを作成して戻り値をラップし、アイデンティティのない単一の値ではなく構造化されたデータを取得します。戻り値が何を意味するのか疑問に思うことはもうありません。それはundefが実際の値ですか、それとも障害の兆候ですか?戻り値が定義されている場合、またはそれが真である場合、それは良いですか?オブジェクトはこれらのことを教えてくれます。また、dieで同じオブジェクトを使用できます。 dieですでにオブジェクトを使用していて、それを戻り値として使用している場合、$@を許容するために必要なすべての追加のことを推奨することはほとんどありません。

これについては、 "例外をスローする代わりにエラーオブジェクトを返す" で詳しく説明します。

ただし、他の人がやっていることを手伝うことはできないので、Perlに例外があると見せかける必要があります。

34
brian d foy

それは常に個人的な好みのケースでした。あなたのお好みは

_my $rv;
if (!eval { $rv = f(); 1 } ) {
   ...
}
_

または

_my $rv = try {
   f();
} catch {
   ...
};
_

ただし、後者はanon subsを使用するため、returnだけでなく、nextなども使用することに注意してください。 Try :: Tinyのtry-catchは、catchブロックとその外側の間に通信チャネルを追加すると、はるかに複雑になる可能性があります。

例外で戻るための最良のケース(最も簡単な)シナリオは、例外がないときに_$rv_が常にtrueである場合です。次のようになります。

_my $rv;
if ($rv = eval { f() }) {
   ...
   return;
}
_

_my $rv = try {
   f();
} catch {
   ...
};

if (!$rv) {
   return;
}
_

そのため、私は Try :: Tiny の代わりに TryCatch を使用しましたが、そのようなモジュールを使用しました。

Perlへの変更は、単にif ($@)を再度実行できることを意味します。言い換えると、

_my $rv;
if (!eval { $rv = f(); 1 } ) {
   ...
}
_

書くことができます

_my $rv = eval { f() };
if ($@) {
   ...
}
_
30
ikegami

他に何もない場合でも、Try::Tinyは依然として素晴らしい構文糖衣です。もう少し重いものが必要な場合は、 TryCatch も使用できます。これにより、Try::Tinyの句がサブルーチンであるという事実に関連するいくつかの問題が解決されます(たとえば、returnは囲み関数を残しません)。

14
duskwuff

Try::Tinyは簡単で軽量です。簡単すぎる。 2つの問題がありました。

  • anonymous subs-内部の 'return'ステートメントには常に問題がありました
  • 常にすべてをキャッチ

そこで、Try::Tinyにいくつかの変更を加えました。今私たちは持っています:

try sub {},
catch 'SomeException' => sub {},
catch [qw/Exception1 Exception2/] => sub {},
catch_all sub {};

私は知っています-この構文は少し変わっていますが、明白な 'sub'のおかげで、プログラマーは 'return'ステートメントが例外ハンドラーからのみ終了し、常にこの例外のみをキャッチすることを知っていますキャッチしたいもの:)

10
msztolcman

次のいずれかを実行します。

local $@;
eval { … }

…$ @への変更がグローバルスコープに影響しないようにするか、Try :: Tinyを使用します。

構文的には、どちらか一方を好む状況があります。

0
Nomad128