Re: : symbol-function vs defun question

steve gonedes <[email protected]>
Newsgroups gmane.lisp.steel-bank.general
Message-ID <[email protected]>

On 3/24/24 06:53, Jeff Cunningham wrote:
> Greetings.
> 
> I have been puzzling over a difference between using SYMBOL-FUNCTION
> and DEFUN within a let binding.  Here's a contrived example that
> illustrates:
> 
> (let ((table1 (make-hash-table)) (table2 '(1 2 3)))
>    (setf (symbol-function (intern "DESCRIBE-SOME-TABLES"))
>          (lambda () (print (list :table1 table1 :table2 table2))))
>    (defun a-function () (describe-some-tables)))
> 
> When this is compiled the first time, the compiler issues the warning:
> 
> ;   Undefined function:
> ;     DESCRIBE-SOME-TABLES
> ;   caught 1 STYLE-WARNING condition
> 
> Yet the function works:
> 
> (a-function)
> ;; => (:TABLE1 #<HASH-TABLE :TEST EQL :COUNT 0 {1003B80DA3}> :TABLE2 (1 2 3))
> 
> Compiled subsequent times the warning is gone - presumably as the package namespace now knows about the function. But unbind it:
> 
> (fmakunbound 'describe-some-tables)
> 
> and recompile and the warning is back the first time.
> 
> Yet if I use DEFUN there is no such warning:
> 
> (let ((table1 (make-hash-table)) (table2 '(1 2 3)))
>    (defun describe-some-tables ()
>      (print (list :table1 table1 :table2 table2)))
>    (defun a-function () (describe-some-tables)))
> 
> Why is this? And is there a way to get around it so I can define the
> function using symbol-function? The reason for doing this is to be
> able to define functions within macros whose names are composed from
> its arguments.
> 
> Thanks.
> 
> -- Jeff
> 

yes, but you must use some black magic though.

(fmakunbound 'describe-some-tables)
(fmakunbound 'a-function)

(defvar DESCRIBE-SOME-TABLES)
(defvar A-FUNCTION)


(let ((table1 (make-hash-table))
       (table2 '(1 2 3)))
   (setf (symbol-function (intern "DESCRIBE-SOME-TABLES"))
         (function (lambda () (list :table1 table1 :table2 table2))))
   )

(defun a-function () (describe-some-tables))


this may not be what you are looking for. the use of defvar with no 
value is ancient evil from systems that have dynamic scope (like emacs).

The use of setf is the reason why your example works. if you want to 
better understand try reading emacs elisp documentation "variable scoping".

there is a non standard `make-named-lambda' or some such degree; this 
would work, but it is used for automatic function generation. I have 
been using the docstrings for years.

  SBCL> (macroexpand-1 '(defun this () nil))
(PROGN
  (EVAL-WHEN (:COMPILE-TOPLEVEL) (SB-C:%COMPILER-DEFUN 'THIS T NIL NIL))
  (SB-IMPL::%DEFUN 'THIS
                   (SB-INT:NAMED-LAMBDA THIS
                       NIL
                     (BLOCK THIS NIL))))
T

if you are not interested in scoping and evaluation i will leave this at 
this.

CL-USER> (inspect 'a-function)

The object is a SYMBOL.
0. Name: "A-FUNCTION"
1. Package: #<PACKAGE "COMMON-LISP-USER">
2. Value: #<unbound slot>
3. Function: #<FUNCTION A-FUNCTION>
4. Plist: NIL
 >


the most obvious to me is the evaluation time.
(EVAL-WHEN (:COMPILE-TOPLEVEL) ...)

could add eval at toplevel, sbcl being mostly a complier and does not do 
this sort of thing.

hopefully this is helpful.

CL-USER> (setf (symbol-value 'a-function) "hello!")
"hello!"
CL-USER> a-function
"hello!"
CL-USER> (funcall #'a-function)
(:TABLE1 #<HASH-TABLE :TEST EQL :COUNT 0 {100470D553}> :TABLE2 (1 2 3))
CL-USER>


in lisp symbols are data types. they have function cells, value cells, 
and property cells. kinda like object pascal.

so think; function and values are both in the same 'symbol'.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.