unofficial mirror of guile-user@gnu.org 
 help / color / mirror / Atom feed
* Exceptions that pass continuations
@ 2013-07-19 10:39 Panicz Maciej Godek
  2013-07-19 13:00 ` Thien-Thi Nguyen
  0 siblings, 1 reply; 5+ messages in thread
From: Panicz Maciej Godek @ 2013-07-19 10:39 UTC (permalink / raw)
  To: guile-user@gnu.org

[-- Attachment #1: Type: text/plain, Size: 2699 bytes --]

Recently I had to solve the following design problem:
I was implementing a high-level wrapper for OpenGL
lights. In order to use the lights, I had to allocate them
before drawing an OpenGL scene, and then release
them after the scene has been drawn.

Initially, I wrote a comment in the function that allocated
the lights that they need to be deallocated. I though,
however, that this is insufficient, because if I ever decided
to reuse the function that allocated the light, I'd need to
read its source code again (which isn't a common practice
-- when I use a function, I'm only interested in what the
function is doing, and not -- how it's doing that)

Instead I finally decided to guarantee that the caller
is at least aware that the light needs to be deallocated,
so that even if it decides to ignore the deallocation, it
does so consciously.

I came up with the idea to throw an exception with current
continuation. The caller can do whatever is needed to later
release the resources, and then call the received continuation.

I wrapped it in the following constructs:

(define (demand to-do-something-with . args)
  (call/cc (lambda(go-on)
             (apply throw 'demand go-on to-do-something-with args)))
  ;; for some reason, the code fails to work without the following
  ;; empty (begin) form
  (begin))

(define-syntax supply
  (syntax-rules ()
    ((_ (((do-something-with . args) do-what ...) ...)
        actions ...)
     (let ((handlers (make-hash-table))
           (unsupported (lambda details
                          (apply throw 'unsupported-reminder
                                 details))))
       (hash-set! handlers (quote do-something-with)
                  (lambda args do-what ...))
       ...
       (catch 'demand
         (lambda () actions ...)
         (lambda (key go-on memorandum . subjects)
           (apply (hash-ref handlers memorandum unsupported) subjects)
           (go-on)))))))

and the whole thing can be used as follows

(let ((resources '()))
  (supply (((release-resource r)
               (set! r (cons r resources))))
    (let ((r (allocate-resource)))
      (demand 'release-resource r)
      (do-something-constructive-with r)))
  (for-each release-resource resources))

(of course, this makes little sense if the
resource is released within the same
procedure it is allocated, but if the release
cannot be performed locally, it seems the
right thing)

I wonder whether this design pattern has ever
been used before, or if there are any potential
flaws with its application.

The advantage is that it reduces the congnitive
load of the programmer: there's less to remember,
because unsatisfied demands remind about
themselves.

Regards

[-- Attachment #2: Type: text/html, Size: 3591 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2013-07-19 16:14 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-07-19 10:39 Exceptions that pass continuations Panicz Maciej Godek
2013-07-19 13:00 ` Thien-Thi Nguyen
2013-07-19 13:52   ` Panicz Maciej Godek
2013-07-19 16:14     ` Thien-Thi Nguyen
2013-07-19 14:12   ` Taylan Ulrich B.

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).