On Tue, May 15, 2018 at 1:28 AM, Matthew Butterick <m...@mbtype.com> wrote:
> To add to your pile of options, because you said "certain error conditions":
> perhaps you might `raise` an exception in the db code that gets caught by
> the network code (using `with-handlers`). In this way the dependency only
> runs one direction (network module imports db module) but the db module can
> still propagate messages to the network module (by going "backward" through
> the existing calling chain with an exception, rather than "forward" by
> calling into the db module).
> Here is a toy example of a `db` module that keeps kicking back an exception
> to a `network` module until it gets zero, no circularity needed:
> #lang racket
> (module db racket
>   (provide f)
>   (define (f val)
>     (if (zero? val)
>         'finally-a-zero!
>         (raise val))))
> (module network racket
>   (require (submod ".." db))
>   (let loop ([maybe-err-int #f])
>     (with-handlers ([integer? loop])
>       (when maybe-err-int
>         (displayln (number->string maybe-err-int)))
>       (f (random 10)))))
> (require 'network)

Brilliant!  That's perfect, thank you.

On that subject, I note the existence of handy/try on the package
server.  It provides a macro for exception handling that combines
'with-handlers' and 'dynamic-wind' while having better end weight than
the former.  It comes in several flavors, the most general of them

(try [(do database thing here)  (write files to disk)]
      [pre (mark records in DB as locked and lock files on disk before
the main body of the try runs)]
      [catch (exn:fail:db (lambda (e) (displayln (~a "Database failed
with message: " (exn-message e)))))
                 (exn:fail:filesystem (lambda (e) (displayln (~a
"failed to write file: " (exn-message e)))))]
      [finally (unlock records in DB, unlock files)])

This reduces to:

(with-handlers ([(exn:fail:db (lambda (e) (displayln (~a "Database
failed with message: " (exn-message e)))))]
                         [(exn:fail:filesystem (lambda (e) (displayln
(~a "failed to write file: " (exn-message e)))))])
     (thunk (mark records in DB as locked and lock files on disk
before the main body of the try runs))
     (thunk (do database thing here)  (write files to disk))
     (thunk (unlock records in DB, unlock files))))

I believe the 'try' version to be better because it is syntactically
simpler, explicitly labels the different parts of the 'dynamic-wind'
instead of requiring that you know what they are, and provides better
end weight in the 'with-handlers' -- the body of the code is up front
so you know what is supposed to happen, while the error handling /
preflight / cleanup are tucked away at the end so that you already
know the context and don't need to think about them while dealing with
the happy path.

The 'pre', 'catch', and 'finally' blocks are all optional and leaving
them out simply defatalizes and returns the exception if there is one.
I should create a version that lets you put 'pre' ahead of the body if
that's what you want, but I haven't done that yet.

> On May 14, 2018, at 10:28 AM, David Storrs <david.sto...@gmail.com> wrote:
> This worked fine until now, but I've gotten to a point where they're
> circular -- the network code needs to receive the chunk and then
> forward it to the DB code, but if certain error conditions come up
> then the DB code needs to tell the network code to re-request the
> data.
> There's various ways I could work around this (simplest being to put
> all the functions in one file), but I'm wondering if there's a
> recommended way?  C would solve this with a .h file.  Perl would solve
> it with function prototypes (or simply be able to sort it out without
> intervention).  What is the preferred Racket way, or am I simply not
> thinking about it correctly?

You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to