あなたは十分なレベルで考えていません。OK、ビルダーは失敗します。属性は未定義のままです。しかし、アクセサーを呼び出しているコードについてはどうしますか?クラスのコントラクトは、メソッドを呼び出すと常にIO::Fileが返されることを示していました。しかし今、それはundefを返しています。(契約はIO::File
そうではありませんでしMaybe[IO::File]
たね?)
したがって、コードの次の行で、呼び出し元は死にます( "the_caller.pl行42の未定義の値でメソッド'readline'を呼び出すことはできません。")。これは、クラスが定義したコントラクトに従うことを期待しているためです。 。失敗はあなたのクラスがすることになっていたことではありませんでした、しかし今それはしました。発信者はこの問題を修正するためにどのように何かを行うことができますか?
を処理できる場合undef
、呼び出し元は実際にはファイルハンドルを最初から必要としませんでした...では、なぜオブジェクトにファイルハンドルを要求したのでしょうか。
それを念頭に置いて、唯一の正しい解決策は死ぬことです。あなたはあなたが同意した契約を満たすことができず、あなたdie
がその状況から抜け出すことができる唯一の方法です。だからそれをするだけです。死は人生の事実です。
これで、ビルダーの実行時に死ぬ準備ができていない場合は、失敗する可能性のあるコードの実行時に変更する必要があります。オブジェクト構築時に、レイジーでないようにするか、BUILD(BUILD { $self->file_name }
)で属性を明示的に有効化することにより、これを行うことができます。
より良いオプションは、ファイルハンドルを外部にまったく公開せず、代わりに次のようなことを行うことです。
# dies when it can't write to the log file
method write_log {
use autodie ':file'; # you want "say" to die when the disk runs out of space, right?
my $fh = $self->file_handle;
say {$fh} $_ for $self->log_messages;
}
これで、プログラムがいつ終了するかがわかりました。、new
またはでwrite_log
。ドキュメントがそう言っているのであなたは知っています。
2番目の方法は、コードを非常にクリーンにします。コンシューマーは、クラスの実装について知る必要はありません。ログメッセージを書き込むように指示できることを知っている必要があります。これで、呼び出し元は実装の詳細に関心がなくなります。本当にやりたかったことをクラスに伝えるだけです。
そして、死ぬwrite_log
ことはあなたが(キャッチブロックで)回復できるものでさえあるかもしれませんが、「とにかくあなたが知らないはずのこのランダムな不透明なものを開くことができなかった」は発信者が回復するのがはるかに難しいです。
基本的に、コードを適切に設計し、例外が唯一の答えです。
(とにかく「彼らは恨みです」という全体を理解することはできません。C++でもまったく同じように機能し、JavaやHaskell、その他すべての言語でも非常によく似ています。この言葉die
は本当に怖いのでしょうか?)