Factor's error system has three pieces: throw to signal an error,
recover to handle one, and ERROR: to define your own kind of
error.
throwthrow (in kernel) raises an error. The argument can be
any value — a string, a number, or a tuple — and it becomes the
error you can later inspect:
! DOCTEST: SKIP
"file not found" throw
throw does not return; the rest of the current word is skipped.
recoverrecover (in continuations) is Factor's
try/catch. It takes a try quotation and a recovery quotation:
recover ( try recovery -- )
If try finishes without throwing, recovery is ignored. If try
throws, the error is pushed onto the stack and recovery is run:
[ "boom" throw ] [ drop "caught" ] recover .
! => "caught"
[ "ok" ] [ drop "never runs" ] recover .
! => "ok"
when from kernel is the natural companion: it runs a
quotation only when the top of stack is truthy:
: check-positive ( n -- )
0 < [ "negative!" throw ] when ;
ERROR:ERROR: defines a tuple class and a word that constructs a fresh
instance and throws it:
! DOCTEST: SKIP
ERROR: not-found path ;
"/missing" not-found
! throws T{ not-found { path "/missing" } }
A no-slot error is just ERROR: name ; — calling name throws an
empty instance. Tuples defined with ERROR: carry a class predicate
name? you can use to test whether a caught error was of that type.
A caught error is just a tuple, so each ERROR: slot comes with the
same auto-generated slot>> reader as any other tuple.
! DOCTEST: SKIP
{
T{ not-found { path "/a" } }
T{ not-found { path "/b" } }
}
[ path>> ] map . ! => { "/a" "/b" }
Elena, the new quality manager at a newspaper factory, asks you to write a small piece of software to monitor the production room.
Define an error tuple class machine-error using the ERROR: parsing
word. It needs no slots.
machine-error ! throws a fresh machine-error
Define check-humidity. It takes a humidity reading off the stack
and throws the string "humidity too high" when the reading is
strictly greater than 70. Otherwise, it returns nothing.
50 check-humidity ! returns nothing
80 check-humidity ! throws "humidity too high"
Define check-temperature. It takes a temperature reading and
throws the string "temperature too high" when the reading is
strictly greater than 500. Otherwise, it returns nothing.
400 check-temperature ! returns nothing
600 check-temperature ! throws "temperature too high"
Define monitor to take a humidity and temperature off the stack and
run both checks. If either check throws, monitor should throw a
fresh machine-error instead. If both pass, monitor returns
nothing.
50 400 monitor ! returns nothing
80 400 monitor ! throws a machine-error
50 600 monitor ! throws a machine-error
Define monitor-batch to take an array of { humidity temperature }
readings and return how many of them would fail (i.e., how many would
cause monitor to throw).
{ { 50 400 } { 80 400 } { 50 600 } { 60 200 } } monitor-batch .
! => 2
Sign up to Exercism to learn and master Factor with 47 concepts163 exercises, and real human mentoring, all for free.