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

* Re: Exceptions that pass continuations
  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 14:12   ` Taylan Ulrich B.
  0 siblings, 2 replies; 5+ messages in thread
From: Thien-Thi Nguyen @ 2013-07-19 13:00 UTC (permalink / raw)
  To: Panicz Maciej Godek; +Cc: guile-user@gnu.org

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

() Panicz Maciej Godek <godek.maciek@gmail.com>
() Fri, 19 Jul 2013 12:39:55 +0200

   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.

Maybe i'm missing something about this particular situation, but i
think generally, the open-use-close pattern in the presence of gc is
best handled by SMOBS and guardians.  The resource is "opened" on SMOB
construction, used for some time and then either explicitly "closed"
(and forgotten) or forgotten.  The guardian notes the state (still
open, already closed) of its objects and closes the ones that need it.

In this case, are OpenGL "lights" not amenable to wrapping as a SMOB?

-- 
Thien-Thi Nguyen
   GPG key: 4C807502
   (if you're human and you know it)
      read my lisp: (responsep (questions 'technical)
                               (not (via 'mailing-list)))
                     => nil

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

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

* Re: Exceptions that pass continuations
  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.
  1 sibling, 1 reply; 5+ messages in thread
From: Panicz Maciej Godek @ 2013-07-19 13:52 UTC (permalink / raw)
  To: Thien-Thi Nguyen; +Cc: guile-user@gnu.org

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

2013/7/19 Thien-Thi Nguyen <ttn@gnu.org>

> () Panicz Maciej Godek <godek.maciek@gmail.com>
> () Fri, 19 Jul 2013 12:39:55 +0200
>
>    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.
>
> Maybe i'm missing something about this particular situation, but i
> think generally, the open-use-close pattern in the presence of gc is
> best handled by SMOBS and guardians.  The resource is "opened" on SMOB
> construction, used for some time and then either explicitly "closed"
> (and forgotten) or forgotten.  The guardian notes the state (still
> open, already closed) of its objects and closes the ones that need it.
>
> In this case, are OpenGL "lights" not amenable to wrapping as a SMOB?
>
>
I've been considering making new type for lights -- perhaps that would
be a little more introspective -- but it turned out more efficient to
represent them in straightforward manner as integers.
However, the thing with the lights is that they need to be disabled
explicitly -- otherwise the lights that are no longer needed would
still lit the scene until the garbage collector decides to disable them.

Of course, I could call gc explicitly, but that would result in too big
overhead (I have tried before to run gc after rendering each frame,
but the CPU usage grew considerably; now I call it after every 64
frames or so). I could also disable all the lights after the scene
is rendered, requiring to initialize them again and again before
rendering a new frame. I think that it would do.

Also, I recently read an article about garbage collector in mobile
apps, and perhaps having some means to do without it would
be a nice option. Here's the link:
http://sealedabstract.com/rants/why-mobile-web-apps-are-slow/

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

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

* Re: Exceptions that pass continuations
  2013-07-19 13:00 ` Thien-Thi Nguyen
  2013-07-19 13:52   ` Panicz Maciej Godek
@ 2013-07-19 14:12   ` Taylan Ulrich B.
  1 sibling, 0 replies; 5+ messages in thread
From: Taylan Ulrich B. @ 2013-07-19 14:12 UTC (permalink / raw)
  To: Panicz Maciej Godek; +Cc: guile-user@gnu.org

I agree with Thien on that all resource-management should be delegated
to the garbage collector via smob types.

However, I found this supply-demand pattern quite neat (could have other
uses perhaps), was kind of bored, with a little free time on my hands,
and enjoy an occasional exercise in delimited continuations, so here's a
cleaned-up version of the code using prompts. :D  But see the note at
the end.

(define prompt-tag (make-prompt-tag "supply"))

(define-syntax supply
  (syntax-rules ()
    ((_ (((action-name . action-args) abody abody* ...) ...) body body* ...)
     (let ((actions (alist->hash-table
                     `((,action-name . ,(lambda action-args
                                          abody abody* ...))
                       ...))))
       (call-with-prompt
        prompt-tag
        (lambda () body body* ...)
        (lambda (cont demanded-action . args)
          (let ((action (hash-table-ref/default actions demanded-action #f)))
            (if action
                (cont (apply action args))
                (apply throw 'demand-not-supplied demanded-action args)))))))))

(define (demand action-name . args)
  (apply abort-to-prompt prompt-tag action-name args))

;;; It composes neatly:
(supply ((('foo . bar) bar)) (demand 'foo 0 1 2)) ;=> (0 1 2)


Now there's something funny to notice here.  I was uncomfortable forcing
the action-names to be literals, because then one couldn't rename them
and thus different modules would get name-clashes; so I don't
automatically quote the action-name, and would expect modules to export
the "names" of the actions they demand as variables holding unique
objects (e.g. a uniquely allocated cons cell), so those variables can be
renamed and the action they refer to is still unique.  And at that
point, we pretty much re-implemented parameters!  In a much worse way
than their Guile-native implementation of course, and forcing their
values to be procedures.

Long story short, use parameters for this pattern. :)

Taylan



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

* Re: Exceptions that pass continuations
  2013-07-19 13:52   ` Panicz Maciej Godek
@ 2013-07-19 16:14     ` Thien-Thi Nguyen
  0 siblings, 0 replies; 5+ messages in thread
From: Thien-Thi Nguyen @ 2013-07-19 16:14 UTC (permalink / raw)
  To: Panicz Maciej Godek; +Cc: guile-user@gnu.org

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

() Panicz Maciej Godek <godek.maciek@gmail.com>
() Fri, 19 Jul 2013 15:52:30 +0200

   > In this case, are OpenGL "lights" not amenable to wrapping as a SMOB?

   I've been considering making new type for lights -- perhaps that
   would be a little more introspective -- but it turned out more
   efficient to represent them in straightforward manner as integers.

   However, the thing with the lights is that they need to be disabled
   explicitly -- otherwise the lights that are no longer needed would
   still lit the scene until the garbage collector decides to disable
   them.

If the integers are small, non-negative and disjoint, and the usage is
always plural (i.e., a "set of lights"), then you might consider using a
bit vector to model the set.

But a bit vector (alone) strikes me as very spartan.  Surely, there must
be some other state associated w/ a "light", such as color, intensity or
direction?  If so, then perhaps a bit vector plus a (compacted) struct
(accessible from both C and Scheme) might do the trick.  I suppose it's
high time to go educate myself before i spew further foolishness...

   Also, I recently read an article about garbage collector in mobile
   apps, and perhaps having some means to do without it would
   be a nice option. Here's the link:
   http://sealedabstract.com/rants/why-mobile-web-apps-are-slow/

Well, mobile apps is something i'm even MORE ignorant of (than OpenGL),
so i'll just say thanks for the link, and bow out of this thread now.

-- 
Thien-Thi Nguyen
   GPG key: 4C807502
   (if you're human and you know it)
      read my lisp: (responsep (questions 'technical)
                               (not (via 'mailing-list)))
                     => nil

[-- Attachment #2: Type: application/pgp-signature, Size: 197 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).