Hi all,

This is more curiosity than a problem.

I am writing a web service which uses a database and there is a fair bit of boilerplate exception handling code which is needed in just about every servlet. It takes up a lot of page and indentation space in the source and just offends my sensibilities. I have created a macro to condense the visual, but I'm not entirely happy with it because of how it deals with interactions among the template, the body and the surrounding code.

As used inline, everything I am doing fits into the following pattern:

  (let [
        (err-msg #f)
       ]

    :

    ; --- start boilerplate
    (let/ec fail-network
      (with-handlers [
                      (exn:fail:network?
                       (lambda (e)
                         (set! err-msg "database connection error")
                         (fail-network)))
                     ]
        (let [
              (db (connect-database))
             ]

          (let/ec fail-sql
            (with-handlers [
                            (exn:fail:sql?
                             (lambda (e)
                               (let [(info (exn:fail:sql-info e))]
                                 (set! err-msg (cdr (assoc 'message info)))
                                 (fail-sql))))
                           ]

              (call-with-transaction db
                (lambda ()
                  :
                  < body ... >
                  :
                  )
                #:isolation 'repeatable-read)

              )

          (disconnect db))

        )))
    ; --- end boilerplate


    ; err-msg needed here

    )


The problems, of course, are that "err-msg" is external to the boilerplate code, and "db" is internal to it. The exception handlers in the boilerplate need access to "err-msg" (or whatever the actual variable name might be) and code in the <body> needs to reference "db" which is only defined within the scope of the macro.

I've gotten it to work with syntax-rules by passing the problem names in as arguments:

(define-syntax with-database
  (syntax-rules ()
    ((with-database-connection db err-msg body ...)
       ... )))

knowing that I can use any names externally or in the body (the above is just example).

This works, but having to pass in the (name of the) required error status variable is ugly. I know I can add a keyword (or several) to handle the status variable, but reasonable syntaxes for it are convoluted. Something like "with-database-connection <JOE> sending errors to <BOB> ..." obviously is possible, but is unwieldy (and un-Scheme-like [ un-Schemely? ] ) - it looks more like Smalltalk or Lisp's loop language than it does like Scheme. 8-)

I suppose I could require to pass in exception handler functions rather than a target for their output, but that also is unwieldy and error prone because the functions have to be inserted at different nesting levels.

Is there some idiomatic way people normally handle this kind of broken abstraction? I've searched a bit trying to find a discussion of something like this, but so far haven't found anything enlightening.

Thanks,
George


____________________
 Racket Users list:
 http://lists.racket-lang.org/users

Reply via email to