Tracks
/
Factor
Factor
/
Exercises
/
Factory Failsafe
Factory Failsafe

Factory Failsafe

Learning Exercise

Introduction

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.

throw

throw (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.

recover

recover (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.

Reading slots back out

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" }

Instructions

Elena, the new quality manager at a newspaper factory, asks you to write a small piece of software to monitor the production room.

1. Define a custom error

Define an error tuple class machine-error using the ERROR: parsing word. It needs no slots.

machine-error   ! throws a fresh machine-error

2. Check the humidity

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"

3. Check the temperature

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"

4. Monitor the machine

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

5. Monitor a batch of readings

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
Edit via GitHub The link opens in a new window or tab
Factor Exercism

Ready to start Factory Failsafe?

Sign up to Exercism to learn and master Factor with 47 concepts163 exercises, and real human mentoring, all for free.