Factorのエラーシステムは、3つの要素からできています。エラーを知らせるthrow、エラーを処理するrecover、そして独自のエラーを定義するERROR:です。
throwthrow(kernelにあります)はエラーを発生させます。引数には文字列・数値・タプルなど、どんな値でも渡すことができ、その値が後から確認できるエラーになります。
! DOCTEST: SKIP
"file not found" throw
throwは戻りません。現在のワードの残りの部分はスキップされます。
recoverrecover(continuationsにあります)は、Factorのtry/catchです。tryクォーテーションとrecoveryクォーテーションを受け取ります。
recover ( try recovery -- )
tryがthrowせずに終われば、recoveryは無視されます。tryがthrowすると、エラーがスタックに積まれ、recoveryが実行されます。
[ "boom" throw ] [ drop "caught" ] recover .
! => "caught"
[ "ok" ] [ drop "never runs" ] recover .
! => "ok"
kernelのwhenは自然な相棒です。スタックの一番上が真と評価されるときだけ、クォーテーションを実行します。
: check-positive ( n -- )
0 < [ "negative!" throw ] when ;
ERROR:ERROR:はタプルクラスと、新しいインスタンスを生成してthrowするワードを定義します。
! DOCTEST: SKIP
ERROR: not-found path ;
"/missing" not-found
! throws T{ not-found { path "/missing" } }
スロットを持たないエラーは、単にERROR: name ;と書くだけです。nameを呼び出すと、空のインスタンスがthrowされます。ERROR:で定義したタプルには、クラスの述語name?が付いており、捕まえたエラーがその型のものかどうかを確かめられます。
捕まえたエラーはただのタプルなので、ERROR:の各スロットには、ほかのタプルと同じ、自動生成されたslot>>リーダーが付いています。
! DOCTEST: SKIP
{
T{ not-found { path "/a" } }
T{ not-found { path "/b" } }
}
[ path>> ] map . ! => { "/a" "/b" }
新聞工場の新しい品質管理責任者であるElenaは、製造室を監視する小さなソフトウェアを書いてほしいと頼んできました。
ERROR:パースワードを使って、エラータプルクラスmachine-errorを定義します。スロットは必要ありません。
machine-error ! throws a fresh machine-error
check-humidityを定義します。これはスタックから湿度の測定値を取り出し、その値が厳密に70より大きいとき、文字列"humidity too high"をthrowします。それ以外の場合は何も返しません。
50 check-humidity ! returns nothing
80 check-humidity ! throws "humidity too high"
check-temperatureを定義します。これは温度の測定値を取り出し、その値が厳密に500より大きいとき、文字列"temperature too high"をthrowします。それ以外の場合は何も返しません。
400 check-temperature ! returns nothing
600 check-temperature ! throws "temperature too high"
monitorを定義し、スタックから湿度と温度を取り出して、両方のチェックを実行します。どちらかのチェックがthrowしたら、代わりにmonitorが新しいmachine-errorをthrowします。両方とも通れば、monitorは何も返しません。
50 400 monitor ! returns nothing
80 400 monitor ! throws a machine-error
50 600 monitor ! throws a machine-error
monitor-batchを定義し、{ humidity temperature }の測定値の配列を受け取って、そのうち何件が失敗するか(つまり、何件がmonitorにthrowさせるか)を返します。
{ { 50 400 } { 80 400 } { 50 600 } { 60 200 } } monitor-batch .
! => 2