On Wed, 01 Feb 2006 09:46:27 +0100, Jan Rychter jan@rychter.com said: "Luís" == Luís Oliveira luismbo@gmail.com:
Luís> "Hoehle, Joerg-Cyril" Joerg-Cyril.Hoehle@t-systems.com writes:
In CLISP, every closure can be turned into a callback, and this is valuable since it allows to retrieve context information out of the closure. Is cffi's limitation caused by some implementations?
Luís> To my knowledge, yes. AFAICT, only SBCL/x86 and CLISP support Luís> that.
Luís> Regarding the behaviour of CFFI:DEFCALLBACK as a non-toplevel Luís> form, not only will it set it globally, the callback itself won't Luís> be generated at runtime on most Lisp, IIRC.
I've just ran into the same problem. I really really need closures as callbacks. I've tried the naive approach:
(defmacro object-event-callback-add (obj type function) `(foreign-funcall "evas_object_event_callback_add" :pointer ,obj callback-type ,(foreign-enum-value 'callback-type type) :pointer (get-callback (defcallback ,(gensym "CB") :void ((data :pointer) (cb-e evas) (cb-obj object) (cb-event :pointer)) (funcall ,function cb-e cb-obj cb-event))) :pointer (null-pointer)))
... but that's a half-baked solution with too many limitations and only works in a simple example that you run once.
What are the problems with unnamed callbacks? My guess was that they will never get garbage-collected, but how about storing all of these in a table somewhere and explicitly freeing them after they are no longer needed? In my case I do have a way of finding out when a callback is no longer needed, and I suspect this is the case for many other applications.
The function evas_object_event_callback_add already makes a closure -- on the C side. You can pass arbitrary data as the last argument and it will be passed to your callback, so you can make data an integer index into an array of Lisp closures. Since you know when a callback is no longer needed, you can recycle the ids quite easily.
It is easy to wrap this up in a function to avoid the code looking like C every time you add a callback.
__Martin