<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto">Hi Madhu,<div><br></div><div>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?<div><br></div><div>Speaking for myself, in general, I am okay with expecting top-level <i>defining forms</i> 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 <b>(defun foo (x) (defun bar (y) (+ x y)))</b> to work.  And I it wouldn’t occur to me to write expressions like <b>(let ((mumble (defvar *quux* 42))) (zerop mumble))</b></div><div><div><br></div><div>It is valuable to Lisp <i>implementers</i> 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 <b>load</b> and the â€œfasdumper” inside <b>compile-file</b>) and, in this case, CCL‘s already powerful FFI. </div><div><br></div><div>One way to think about the legality of this example is to ask yourself: what type of value does <b>ccl:defcallback</b> return? </div><div><br></div><div>The fasdumper can only write certain types of constants to a binary file. This might explain the error message you received. </div><div><br></div><div>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. </div><div><br></div><div>The good news is that Lisp offers tremendous opportunity to think outside the â€œboxes” imposed by <i>other</i> programming languages. It makes me smile every day. </div><div><br id="lineBreakAtBeginningOfSignature"><div dir="ltr">--Tim</div><div dir="ltr"><br><blockquote type="cite">On May 22, 2024, at 02:55, Madhu <enometh@meer.net> wrote:<br><br></blockquote></div><blockquote type="cite"><div dir="ltr"><span>I came across a use of cffi callbacks which defines the callback</span><br><span>within a function. In CCL the following</span><br><span></span><br><span>```</span><br><span>(defun barf ()</span><br><span>  (ccl:defcallback CMPSTRINGP (:address p1 :address p2 :signed-int)</span><br><span>      (ccl:external-call "strcmp" :address p1 :address p2 :signed-int)))</span><br><span>(barf)</span><br><span></span><br><span>=></span><br><span>Condition of type TYPE-ERROR:</span><br><span></span><br><span>The value (:INTERNAL CMPSTRINGP BARF) is not of the expected type</span><br><span> (AND SYMBOL (NOT (SATISFIES CONSTANTP)))</span><br><span>```</span><br><span></span><br><span>Is there any reason to disallow callbacks defined by defcallbacks from</span><br><span>being closures which capture their environment?</span><br><span></span><br><span>I am attaching a patch which continues to use the name specified by</span><br><span>DEFCALLBACK even if the defining function is a closure.</span><br><span></span><br><span>I'd very much appreciate it if other developers could review it and</span><br><span>give feedback.</span><br><span></span><br><span></span><br>From d6241c160cc42979da2629862f97c350615850a9 Mon Sep 17 00:00:00 2001
From: Madhu <enometh@net.meer>
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

</enometh@net.meer></div></blockquote></div></div></div></body></html>