[Openmcl-devel] should ccl allow ffi callbacks to be defined within closures

Tim McNerney mc at media.mit.edu
Wed May 22 05:59:09 PDT 2024


Hi Madhu,

If I may pose a rhetorical question: what is your operational goal for defining a FFI callback that closes over its lexical environment? Is there perhaps a way you can rewrite your code to avoid the need for a closure?

Speaking for myself, in general, I am okay with expecting top-level defining forms to only be allowed at top-level and not inside arbitrary Lisp expressions. For example, in my professional Lisp work, I have never once needed (defun foo (x) (defun bar (y) (+ x y))) to work.  And I it wouldn’t occur to me to write expressions like (let ((mumble (defvar *quux* 42))) (zerop mumble))

It is valuable to Lisp implementers that these sorts of top-level expressions rules and conventions go unchallenged by users (programmers) so the implementers can write stable and efficient binary loaders and dumpers (the “fasloader” inside load and the “fasdumper” inside compile-file) and, in this case, CCL‘s already powerful FFI. 

One way to think about the legality of this example is to ask yourself: what type of value does ccl:defcallback return? 

The fasdumper can only write certain types of constants to a binary file. This might explain the error message you received. 

I apologize if this message seems adversarial or too much like a lecture. I am only trying to offer insights into how a Lisp programmer such as myself navigates through the language’s restrictions by “thinking inside the box.” Yes, sometimes the “box” is not the easiest to “wrap one’s head around.” Initially, it took me years to absorb the conventions and unwritten rules. 

The good news is that Lisp offers tremendous opportunity to think outside the “boxes” imposed by other programming languages. It makes me smile every day. 

--Tim

> On May 22, 2024, at 02:55, Madhu <enometh at meer.net> wrote:
> 
> I came across a use of cffi callbacks which defines the callback
> within a function. In CCL the following
> 
> ```
> (defun barf ()
>  (ccl:defcallback CMPSTRINGP (:address p1 :address p2 :signed-int)
>      (ccl:external-call "strcmp" :address p1 :address p2 :signed-int)))
> (barf)
> 
> =>
> Condition of type TYPE-ERROR:
> 
> The value (:INTERNAL CMPSTRINGP BARF) is not of the expected type
> (AND SYMBOL (NOT (SATISFIES CONSTANTP)))
> ```
> 
> Is there any reason to disallow callbacks defined by defcallbacks from
> being closures which capture their environment?
> 
> I am attaching a patch which continues to use the name specified by
> DEFCALLBACK even if the defining function is a closure.
> 
> I'd very much appreciate it if other developers could review it and
> give feedback.
> 
> 
> From d6241c160cc42979da2629862f97c350615850a9 Mon Sep 17 00:00:00 2001 From: Madhu Date: Sun, 12 May 2024 22:01:08 +0530 Subject: [PATCH] allow ffi callbacks to be defined within closures. * level-1/l1-callbacks.lisp: (define-callback-function): If the function-name is an internal-function of the form (:internal name) use the internal name instead. After this patch, defcallbacks can be defined within internal functions. e.g. the following will work, instead of erroring out on the name. ``` (defun barf () (ccl:defcallback CMPSTRINGP (:address p1 :address p2 :signed-int) (ccl:external-call "strcmp" :address p1 :address p2 :signed-int))) (barf) ``` --- level-1/l1-callbacks.lisp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/level-1/l1-callbacks.lisp b/level-1/l1-callbacks.lisp index 3f88041..f147f71 100644 --- a/level-1/l1-callbacks.lisp +++ b/level-1/l1-callbacks.lisp @@ -25,7 +25,10 @@ (defstatic *callback-lock* (make-lock)) (defun define-callback-function (lisp-function &optional doc-string (without-interrupts t) info &aux name trampoline) (unless (functionp lisp-function) (setq lisp-function (require-type lisp-function 'function))) - (unless (and (symbolp (setq name (function-name lisp-function))) + (if (and (consp (setq name (function-name lisp-function))) + (eql (car name) :internal)) + (setq name (second name))) + (unless (and (symbolp name) ;;Might as well err out now before do any _Newptr's... (not (constant-symbol-p name))) (report-bad-arg name '(and symbol (not (satisfies constantp))))) -- 2.39.2.101.g768bb238c4
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.clozure.com/pipermail/openmcl-devel/attachments/20240522/c88ca33b/attachment.htm>


More information about the Openmcl-devel mailing list