[plt-scheme] raising / handling errors

From: Danny Yoo (dyoo at hkn.eecs.berkeley.edu)
Date: Mon Feb 27 18:34:08 EST 2006

> I know(?) how to use with-handlers to catch exististing exceptions, and
> in fact, I do this (now) in my read/eval/print loop. But it is not all
> clear (to me) how to go about raising exceptions and handling them. I am
> aware of raise and error, but I'd like to be able to raise an exception
> which will be caught by a handler I install. I recall reading that, say,
> exn:fail:contract:arity corresponds to the predicate
> exn:fail:contract:arity?


Hi Greg,

Here's a small example; let's say that we're writing a function that only
works with numbers and we'd like to raise a you-are-silly exception if we
give that function something else.  (We really should use contracts here,
but let's ignore that for the moment.)


Let's first define a "you-are-silly" kind of exception.  We can do this by
defining an exn:fail:you-are-silly structure:

;;;;;;
> (define-struct (exn:fail:you-are-silly exn:fail) ())
;;;;;;


We're subtyping on exn:fail to make it a little easier to trap it
generically: we might want to trap things by saying something like:

   (with-handlers ((exn:fail? ...)) ...)

in which case, if we raise an exn:fail:you-are-silly, things are still
going to work ok because exn:fail:you-are-silly is a subtype of exn:fail.



But how do we construct an instance of an exn:fail:you-are-silly
structure?  If we look at Chapter 6 of the reference:

http://download.plt-scheme.org/doc/mzscheme/mzscheme-Z-H-6.html#node_chap_6

then we can see a description on primitive exceptions in Section 6.1.1.
A main thing to note is that the base 'exn' structure has two fields.
'exn:fail' doesn't introduce any other fields, so that means that our
'exn:fail:you-are-silly constructor' also takes in only two fields:

    * message
    * continuation-marks


We can experimentally see this:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (procedure-arity make-exn:fail:you-are-silly)
2
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

but it's good to know what those two fields mean too.  *grin*



Ok, so let's try this:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (make-exn:fail:you-are-silly
    "you silly head"
    (current-continuation-marks))
#<struct:exn:fail:you-are-silly>
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


There's our exception object.  Its only a matter now of raising it
whenever we want to castigate the caller.


Let's turn this into a procedure and test this out:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (define (raise-you-silly)
    (raise (make-exn:fail:you-are-silly
            "you silly head"
            (current-continuation-marks))))
> (define (test x)
    (cond
      [(number? x) (* x x)]
      [else (raise-you-silly)]))
> (test 42)
1764
> (test 'muhahah)
you silly head
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


I hope this helps!



Posted on the users mailing list.