From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Panicz Maciej Godek Newsgroups: gmane.lisp.guile.user Subject: Exceptions that pass continuations Date: Fri, 19 Jul 2013 12:39:55 +0200 Message-ID: NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/alternative; boundary=bcaec5171ddd8beaeb04e1daf262 X-Trace: ger.gmane.org 1374230405 20409 80.91.229.3 (19 Jul 2013 10:40:05 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Fri, 19 Jul 2013 10:40:05 +0000 (UTC) To: "guile-user@gnu.org" Original-X-From: guile-user-bounces+guile-user=m.gmane.org@gnu.org Fri Jul 19 12:40:07 2013 Return-path: Envelope-to: guile-user@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1V086Z-0006Pr-6u for guile-user@m.gmane.org; Fri, 19 Jul 2013 12:40:07 +0200 Original-Received: from localhost ([::1]:52650 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V086Y-0007FB-Rw for guile-user@m.gmane.org; Fri, 19 Jul 2013 06:40:06 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:57419) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V086P-0007CL-4y for guile-user@gnu.org; Fri, 19 Jul 2013 06:39:59 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1V086N-0001MV-UB for guile-user@gnu.org; Fri, 19 Jul 2013 06:39:57 -0400 Original-Received: from mail-vb0-x236.google.com ([2607:f8b0:400c:c02::236]:48674) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1V086N-0001MO-Pr for guile-user@gnu.org; Fri, 19 Jul 2013 06:39:55 -0400 Original-Received: by mail-vb0-f54.google.com with SMTP id q12so3040019vbe.41 for ; Fri, 19 Jul 2013 03:39:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=xO0j0UmJFFm1suTMnVu1up/ir8TlKPa3OaxUsLAT+T4=; b=QTxoBC+1N23Jp+GOq5aBAYqtuNfsZ3MBybsMpVlrd7D9DoXZomAybINgflYWYSw59G yPTbrCQ0AIWbHna1t/h6alRcekSZTfBCDt+fi7F4msBr6OwvqhqWD13C+ACk21zdpxRz QkVHVLP0uKW2ifUpYdTGf42WXuZxY3gPNyAeqk8A4CwhaIg0VPwsWoM0TCKJ/BKCrCLQ 5sISxRvIMfd2bzQI8KCZd1Nv5BN1/qm/r+2RfVxYYX6+Ll4DdbbLf+Sw9Jileey1XNIg 0SXYjba3llFP3t4HG/srAft05iL97jFdRlf2nLGHODy7a9XFdIQUdXfSNO/ww8k2RY/A +AAQ== X-Received: by 10.52.175.230 with SMTP id cd6mr4661821vdc.25.1374230395216; Fri, 19 Jul 2013 03:39:55 -0700 (PDT) Original-Received: by 10.220.190.199 with HTTP; Fri, 19 Jul 2013 03:39:55 -0700 (PDT) X-detected-operating-system: by eggs.gnu.org: Error: Malformed IPv6 address (bad octet value). X-Received-From: 2607:f8b0:400c:c02::236 X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: General Guile related discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-user-bounces+guile-user=m.gmane.org@gnu.org Original-Sender: guile-user-bounces+guile-user=m.gmane.org@gnu.org Xref: news.gmane.org gmane.lisp.guile.user:10555 Archived-At: --bcaec5171ddd8beaeb04e1daf262 Content-Type: text/plain; charset=ISO-8859-1 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 --bcaec5171ddd8beaeb04e1daf262 Content-Type: text/html; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable
Recently I had to solve the following design problem:
= I was implementing a high-level wrapper for OpenGL=A0
lights. In = order to use the lights, I had to allocate them=A0
before drawing= an OpenGL scene, and then release=A0
them after the scene has been drawn.

Initiall= y, I wrote a comment in the function that allocated
the lights th= at they need to be deallocated. I though,
however, that this is i= nsufficient, because if I ever decided
to reuse the function that allocated the light, I'd need to
<= div>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 d= o whatever is needed to later
release the resources, and then cal= l the received continuation.

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

(define-syntax supply
=A0 (syntax-rules ()
=A0 = =A0 ((_ (((do-something-with . args) do-what ...) ...)
=A0 =A0 =A0 =A0 actions ...)
=A0 =A0 =A0(let ((handlers (mak= e-hash-table))
=A0 =A0 =A0 =A0 =A0 =A0(unsupported (lambda detail= s
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (apply thro= w 'unsupported-reminder
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 = =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0details))))
=A0 =A0 =A0 =A0(hash-set! handlers (quote do-something-with)
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (lambda args do-what ...))
= =A0 =A0 =A0 =A0...
=A0 =A0 =A0 =A0(catch 'demand
= =A0 =A0 =A0 =A0 =A0(lambda () actions ...)
=A0 =A0 =A0 =A0 =A0(lambda (key go-on memorandum . subjects)
=A0 = =A0 =A0 =A0 =A0 =A0(apply (hash-ref handlers memorandum unsupported) subjec= ts)
=A0 =A0 =A0 =A0 =A0 =A0(go-on)))))))

and the whole thing can be used as follows

(let ((resources '()))
=A0 (supply (((rel= ease-resource r)
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(set! r (cons r r= esources))))
=A0 =A0 (let ((r (allocate-resource)))
=A0= =A0 =A0 (demand 'release-resource r)
=A0 =A0 =A0 (do-something-constructive-with r)))
=A0 (for-ea= ch release-resource resources))

(of course, this m= akes 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 wo= nder 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
--bcaec5171ddd8beaeb04e1daf262--