[Openmcl-devel] Calling a callback & closures
David Steuber
david at david-steuber.com
Mon May 2 13:01:32 PDT 2005
Hello Gary & list,
On May 2, 2005, at 7:33 AM, Gary Byers wrote:
> On Mon, 2 May 2005, David Steuber wrote:
>> I'm trying to see if I can use DEFCALLBACK to close over lexical
>> variables so that when a C function calls into lisp, the correct
>> value will be in the variable. I'm not clear how closures work, so I
>> don't even know if the idea is sane. To start testing the idea, I
>> tried using %ff-call to call my callback. I landed in the kernel
>> debugger, so I'm doing something very wrong. Can someone show me how
>> to get this bit to work?
>>
>> $ openmcl
>> Welcome to OpenMCL Version (Beta: Darwin) 0.14.3-050429!
>> ? (%ff-call (let (fn)
>> (declare (special fn))
>> (defcallback fn (:integer)
>> 1)) :integer)
>> Unhandled exception 4 at 0x0639eeec, context->regs at #xf01356d8
>> Illegal instruction (0x0639ef06) at 0x0639eeec In foreign code at
>> address 0x0639eeec
>> ? for help
>> [1019] OpenMCL kernel debugger:
>>
>> I was hoping to get a 1 back.
>
> The form:
>
> (defcallback fn (:integer) 1)
>
> a) has the effect of setting the (special) value of the symbol FN to a
> pointer (to a little piece of foreign code) that jumps into the lisp
> kernel; code in the kernel jumps out to a lisp function.
> b) retuns the symbol FN (as do other defining forms, like
> DEFUN/DEFMACRO.)
>
> If we moved things around:
>
> ? (defcallback fn (:int) 1)
> 1
> ? (%ff-call 'fn :signed-fullword)
>
> and the kernel debugger tells us (somewhat cryptically ...) that
> %FF-CALL
> doesn't do much typechecking and is perfectly happy to try to jump into
> a symbol. (The pointer to the symbol's pname probably isn't a valid
> machine instruction.)
>
> (%ff-call (let (fn)
> (declare (special fn))
> (defcallback fn (:int)
> 1)
> fn)
> :signed-fullword)
>
> returns 1.
Ah! Thanks for correcting the syntax for me.
>> Now imagine that I declared foo in the let expression (but not as a
>> special). Could the value of foo be used in the callback fn?
>>
>> eg (if the above worked):
>>
>> (%ff-call (let (fn (foo 1))
>> (declare (special fn))
>> (defcallback fn (:integer) foo)) :integer)
>>
>
> I'm not sure that I understand the question, so here are a couple
> of (not-necessarily relevant) answers:.
I was asking about making a closure in a clumsy sort of way...
> The functions that DEFCALLBACK defines are defined in the current
> lexical environment, so you can do things like:
>
> ? (let* ((x 17))
> (defcallback fn (:int) x)
> (defun set-x (val)
> (setq x val)))
> SET-X
> ? (set-x 12)
> 12
> ? (ff-call fn :signed-integer)
> 12
>
> DEFCALLBACK has an (often, but not always) useful side-effect: namely,
> setting a special variable's value to point to the little piece of
> trampoline code. (Using DEFCALLBACK to redefine an existing callback
> preserves that pointer but redefines the lisp code associated with
> that foreign pointer.)
>
> It's certainly handy to be able to manipulate globally named callback
> pointers, but it seems (both philosophically and practically) like
> it'd also be handy to be able to create anonymous callback functions
> as well (that the actions of manipulating the callback pointer and
> generating a lisp function that handles the foreign argument/return
> value coercions should/could be separated.)
Yes. Here is what I'm trying to do (in concept) and it looks like it
may work:
$ openmcl
Welcome to OpenMCL Version (Beta: Darwin) 0.14.3-050429!
? (defun make-ff (ret)
(let (fn)
(declare (special fn))
(defcallback fn (:int) ret)
fn))
MAKE-FF
? (defvar ff-foo (make-ff 10))
FF-FOO
? (defvar ff-bar (make-ff 20))
FF-BAR
? (%ff-call ff-foo :signed-fullword)
10
? (%ff-call ff-bar :signed-fullword)
20
? (quit)
The idea is to make a callback that uses a closure to associate the
function pointer with a CLOS object that can then be used by the
callback function. This would get rid of an ugly hack in some Carbon
event handler code I have and also allow me to abstract the notion of
Carbon callbacks as other APIs want different callbacks with different
function signatures (in the C sense of the word).
More information about the Openmcl-devel
mailing list