From: Sascha Wilde
Subject: Idiom to call function from string
Date: 
Message-ID: <4hd4l9F1q0g6kU1@individual.net>
Hi *,

I want to call an existing function after construction it's name from
strings.  I came up with:

(funcall (find-symbol (string-upcase (concatenate 'string 
                                                  "foo-" "bar")) 
                      :baz))

to call function FOO-BAR from package BAZ, which actually works, but
I'm under the impression that that's not very elegant -- so my
question is: is there a standard idom to do this?

cheers
sascha
-- 
Sascha Wilde
Wer HTML postet oder gepostetes HTML quotet oder sich gepostetes oder
gequotetes HTML beschafft, um es in Verkehr zu bringen, wird geplonkt.

From: Barry Margolin
Subject: Re: Idiom to call function from string
Date: 
Message-ID: <barmar-EAF2BE.16310709072006@comcast.dca.giganews.com>
In article <···············@individual.net>,
 Sascha Wilde <·····@sha-bang.de> wrote:

> Hi *,
> 
> I want to call an existing function after construction it's name from
> strings.  I came up with:
> 
> (funcall (find-symbol (string-upcase (concatenate 'string 
>                                                   "foo-" "bar")) 
>                       :baz))
> 
> to call function FOO-BAR from package BAZ, which actually works, but
> I'm under the impression that that's not very elegant -- so my
> question is: is there a standard idom to do this?

I can't think of any more straightforward way than that.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Rob Warnock
Subject: Re: Idiom to call function from string
Date: 
Message-ID: <LcSdnYZVPo5ONCzZnZ2dnUVZ_qOdnZ2d@speakeasy.net>
Sascha Wilde  <·····@sha-bang.de> wrote:
+---------------
| I want to call an existing function after construction it's name from
| strings.  I came up with:
| (funcall (find-symbol (string-upcase (concatenate 'string 
|                                                   "foo-" "bar")) 
|                       :baz))
| to call function FOO-BAR from package BAZ, which actually works,
| but I'm under the impression that that's not very elegant -- so my
| question is: is there a standard idom to do this?
+---------------

From your description, I'm assuming that the "bar" is coming
from external user input, and the "foo-" is a prefix you use
in your application to distinguish functions which may be called
from such external input. If that's the case, you might want to
collect all the names of all the "foo-" functions into a hash
table[1], whereupon the above call turns into:

    (funcall (gethash "bar" *foo-functions*))

But both versions will give an "Undefined function: NIL" (or similar)
error if the input is invalid. The GETHASH version can be easily
adjusted to produce a more user-friendly result, e.g.:

    (funcall (gethash "bar" *foo-functions* 'foo-not-found-function)))

Now as far as *building* that hash table automagically, here's
a case where Common Lisp really shines!

    (defvar *foo-functions* (make-hash-table :test #'equal))

    (defmacro def-foo-function (name &body body)
      `(progn (defun ,name () ,@body)
	      (setf (gethash ,(string-downcase (symbol-name name))
			     *foo-functions*)
                    #',name)))

    (defun foo-dispatch (string)
      (flet ((usage ()
	       (format t "Unknown function: ~s~%~
			 usage: ...whatever...blah...blah...~%"
			 string)))
	(funcall (gethash string *foo-functions* #'usage))))

    ;;; Then simply define all your FOO- functions, e.g.:

    (def-foo-function hello
      (format t "Hello, world!~%"))

    ;;; ...and the rest...

And then your application can simply evoke FOO-DISPATCH:

    > (foo-dispatch "ehllo")
    Unknown function: "ehllo"
    usage: ...whatever...blah...blah...
    NIL
    > (foo-dispatch "hello")
    Hello, world!
    NIL
    > 


-Rob

[1] The hash table needs to be at least an #'EQUAL one, if you're
    using strings as inputs. If you want to ignore input case, then
    make the hash table definition above use :TEST #'EQUALP, and
    remove the STRING-DOWNCASE (or not) from the DEF-FOO-FUNCTION
    definition.

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Rob Warnock
Subject: Re: Idiom to call function from string
Date: 
Message-ID: <1rOdncIuiKBGMCzZnZ2dnUVZ_vOdnZ2d@speakeasy.net>
I just wrote:
+---------------
| Sascha Wilde  <·····@sha-bang.de> wrote:
| +---------------
| | I want to call an existing function after construction it's name from
| | strings.  I came up with:
| | (funcall (find-symbol (string-upcase (concatenate 'string 
| |                                                   "foo-" "bar")) 
| |                       :baz))
...
|     (defmacro def-foo-function (name &body body)
|       `(progn (defun ,name () ,@body)
| 	      (setf (gethash ,(string-downcase (symbol-name name))
| 			     *foo-functions*)
|                     #',name)))
+---------------

Oops! Sorry, I forgot that prefixing the function names with "FOO-"
was part of your spec. Please replace the above DEF-FOO-FUNCTION
with this one:

     (defmacro def-foo-function (name &body body)
       (let ((mangled-name (intern (concatenate 'string
						(symbol-name :foo-)
						(symbol-name name)))))
	 `(progn (defun ,mangled-name () ,@body)
		 (setf (gethash ,(string-downcase (symbol-name name))
				*foo-functions*)
			#',mangled-name))))

[Note that the name-mangling happens only at DEF-FOO-FUNCTION time,
*not* at runtime...]

The rest of the code remains the same as before. [Well, except that
to *completely* conform to your spec, the whole file should start
with (IN-PACKAGE :BAZ).]


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Pascal Bourguignon
Subject: Re: Idiom to call function from string
Date: 
Message-ID: <877j2mkumn.fsf@thalassa.informatimago.com>
····@rpw3.org (Rob Warnock) writes:

> Now as far as *building* that hash table automagically, here's
> a case where Common Lisp really shines!
>
>     (defvar *foo-functions* (make-hash-table :test #'equal))
>
>     (defmacro def-foo-function (name &body body)
>       `(progn (defun ,name () ,@body)
> 	      (setf (gethash ,(string-downcase (symbol-name name))
> 			     *foo-functions*)
>                     #',name)))

If you want to COMPILE-FILE and still use it at run-time after a LOAD
of the .fasl, it'll be a little more complicated, but the principle
stands.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

"Debugging?  Klingons do not debug! Our software does not coddle the
weak."
From: Rob Warnock
Subject: Re: Idiom to call function from string
Date: 
Message-ID: <bu2dnVZQF-5Vgi_ZnZ2dnUVZ_oydnZ2d@speakeasy.net>
Pascal Bourguignon  <···@informatimago.com> wrote:
+---------------
| ····@rpw3.org (Rob Warnock) writes:
| > Now as far as *building* that hash table automagically, here's
| > a case where Common Lisp really shines!
| >     (defvar *foo-functions* (make-hash-table :test #'equal))
| >
| >     (defmacro def-foo-function (name &body body)
| >       `(progn (defun ,name () ,@body)
| > 	          (setf (gethash ,(string-downcase (symbol-name name))
| > 			         *foo-functions*)
| >                     #',name)))
| 
| If you want to COMPILE-FILE and still use it at run-time after
| a LOAD of the .fasl, it'll be a little more complicated...
+---------------

Hunh? I'm generally aware of those issues, but I thought I was
careful to make the macro expand into things that would build
the table at LOAD time, rather than at compile time. Did I miss
something obvious? It works in CMUCL, at least:

    > (compile-file "foo-hash")
    ; Python version 1.1, VM version Intel x86 on 10 JUL 06 02:15:58 am.
    ; Compiling: /u/rpw3/foo-hash.lisp 10 JUL 06 02:11:29 am
    ; Converted DEF-FOO-FUNCTION.
    ; Compiling DEFMACRO DEF-FOO-FUNCTION: 
    ; Converted FOO-DISPATCH.
    ; Compiling DEFUN FOO-DISPATCH: 
    ; Converted FOO-HELLO.
    ; Compiling DEF-FOO-FUNCTION HELLO: 
    ; Converted FOO-BYE.
    ; Compiling DEF-FOO-FUNCTION BYE: 
    ; Byte Compiling Top-Level Form: 
    ; Byte Compiling Top-Level Form: 
    ; foo-hash.x86f written.
    ; Compilation finished in 0:00:01.
    #P"/u/rpw3/foo-hash.x86f"
    NIL
    NIL
    > (load *)

    ; Loading #P"/u/rpw3/foo-hash.x86f".
    T
    > (foo-dispatch "hello")
    Hello, world!
    NIL
    > (foo-dispatch "bye")
    Goodbye, cruel world!
    NIL
    > (foo-dispatch "gorp")
    Unknown function: "gorp"
    usage: ...whatever...blah...blah...
    NIL
    > 

It also works fine if the LOAD of the FASL is in a fresh image.

Or are you talking about adding additional DEF-FOO-FUNCTIONs at
run-time? That seems to work, too:

    > (load "foo-hash")

    ; Loading #P"/u/rpw3/foo-hash.x86f".
    T
    > (foo-dispatch "gorp")
    Unknown function: "gorp"
    usage: ...whatever...blah...blah...
    NIL
    > (def-foo-function gorp ()
	(format t "What is \"gorp\"?~%"))
    > (foo-dispatch "gorp")
    What is "gorp"?
    NIL
    > 

Run-time redefinitions work, too:

    > (def-foo-function gorp ()
	(format t "What is \"gorp\"?~%"))
    > (foo-dispatch "gorp")
    What is "gorp"?
    NIL
    > (def-foo-function gorp ()
	(format t "Gorp is another name for trailmix.~%"))

    #<Interpreted Function FOO-GORP {48935511}>
    > (foo-dispatch "gorp")
    Gorp is another name for trailmix.
    NIL
    > 

I admit that you need a little more mechanism if you want run-time
DEF-FOO-FUNCTION redefinitions to get automatically compiled, but
I'll leave that as "an exercise for the reader"...  ;-}


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Pascal Bourguignon
Subject: Re: Idiom to call function from string
Date: 
Message-ID: <873bd94ud1.fsf@thalassa.informatimago.com>
····@rpw3.org (Rob Warnock) writes:

> Pascal Bourguignon  <···@informatimago.com> wrote:
> +---------------
> | ····@rpw3.org (Rob Warnock) writes:
> | > Now as far as *building* that hash table automagically, here's
> | > a case where Common Lisp really shines!
> | >     (defvar *foo-functions* (make-hash-table :test #'equal))
> | >
> | >     (defmacro def-foo-function (name &body body)
> | >       `(progn (defun ,name () ,@body)
> | > 	          (setf (gethash ,(string-downcase (symbol-name name))
> | > 			         *foo-functions*)
> | >                     #',name)))
> | 
> | If you want to COMPILE-FILE and still use it at run-time after
> | a LOAD of the .fasl, it'll be a little more complicated...
> +---------------
>
> Hunh? I'm generally aware of those issues, but I thought I was
> careful to make the macro expand into things that would build
> the table at LOAD time, rather than at compile time. Did I miss
> something obvious? It works in CMUCL, at least:
> It also works fine if the LOAD of the FASL is in a fresh image.
> [...]
> Or are you talking about adding additional DEF-FOO-FUNCTIONs at
> run-time? That seems to work, too:
> [...]
> Run-time redefinitions work, too:
> [...]
> I admit that you need a little more mechanism if you want run-time
> DEF-FOO-FUNCTION redefinitions to get automatically compiled, but
> I'll leave that as "an exercise for the reader"...  ;-}

sbcl is more finicky: we must put the macro and the functions they use
in (eval-when (:compile-toplevel :load-toplevel :execute) ...).
But otherwise, you're right, we don't need anything more to have the
data saved and loaded in the fasl file.  Sorry.



[···@thalassa tmp]$ sbcl

#<PACKAGE "COMMON-LISP-USER"> 
;; Reading ASDF packages from /home/pjb/asdf-central-registry.data...
; loading system definition from
; /usr/local/languages/sbcl/lib/sbcl/sb-bsd-sockets/sb-bsd-sockets.asd into
; #<PACKAGE "ASDF0">
; registering #<SYSTEM SB-BSD-SOCKETS {AD01A99}> as SB-BSD-SOCKETS
; registering #<SYSTEM SB-BSD-SOCKETS-TESTS {B089471}> as SB-BSD-SOCKETS-TESTS
; loading system definition from
; /usr/local/languages/sbcl/lib/sbcl/sb-posix/sb-posix.asd into
; #<PACKAGE "ASDF0">
; registering #<SYSTEM SB-POSIX {A8F7F71}> as SB-POSIX
; registering #<SYSTEM SB-POSIX-TESTS {AA7F4E1}> as SB-POSIX-TESTS
~/.sbclrc loaded
* (cd "/tmp/")

#P"/tmp/"
* (cat "foo.lisp")
(defvar *foo-functions* (make-hash-table :test #'equal))

(defmacro def-foo-function (name &body body)
  `(progn (defun ,name () ,@body)
          (setf (gethash ,(string-downcase (symbol-name name))
                         *foo-functions*)
                #',name)))


(defun foo-dispatch (string)
  (flet ((usage ()
	       (format t "Unknown function: ~s~%~
			 usage: ...whatever...blah...blah...~%"
                   string)))
	(funcall (gethash string *foo-functions* #'usage))))

;;; Then simply define all your FOO- functions, e.g.:

(def-foo-function hello
    (format t "Hello, world!~%"))

;;; ...

(def-foo-function fail? ()
  (format t "Do I fail?~%"))

(eval-when (:compile-toplevel)
  (format t "At compilation-time: ") (foo-dispatch "fail?"))

(eval-when (:load-toplevel)
  (format t "At load-time: ") (foo-dispatch "fail?"))

(eval-when (:execute)
  (format t "At run-time: ") (foo-dispatch "fail?"))


* (compile-file "foo.lisp")

; compiling file "/tmp/foo.lisp" (written 10 JUL 2006 12:29:27 PM):
; compiling (DEFVAR *FOO-FUNCTIONS* ...)
; compiling (DEFMACRO DEF-FOO-FUNCTION ...)
; compiling (DEFUN FOO-DISPATCH ...)
; compiling (DEF-FOO-FUNCTION HELLO ...)
; compiling (DEF-FOO-FUNCTION FAIL? ...)At compilation-time: 
debugger invoked on a UNDEFINED-FUNCTION: The function FOO-DISPATCH is undefined.

Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.

restarts (invokable by number or by possibly-abbreviated name):
  0: [ABORT] Exit debugger, returning to top level.

(SYMBOL-FUNCTION FOO-DISPATCH)
0] 0
; 
; compilation unit aborted
;   caught 1 fatal ERROR condition

; compilation aborted after 0:00:02

;;----------------------------------------------------------------------
;; We must put the macro and the functions they use
;;  in (eval-when (:compile-toplevel :load-toplevel :execute)
;;----------------------------------------------------------------------

* (cat "foo.lisp")
(eval-when (:compile-toplevel :load-toplevel :execute)
  (defvar *foo-functions* (make-hash-table :test #'equal))

  (defmacro def-foo-function (name &body body)
    `(progn (defun ,name () ,@body)
            (setf (gethash ,(string-downcase (symbol-name name))
                           *foo-functions*)
                  #',name)))

  (defun foo-dispatch (string)
    (flet ((usage ()
             (format t "Unknown function: ~s~%~
			 usage: ...whatever...blah...blah...~%"
                     string)))
      (funcall (gethash string *foo-functions* #'usage)))))

;;; Then simply define all your FOO- functions, e.g.:

(def-foo-function hello
    (format t "Hello, world!~%"))

;;; ...

(def-foo-function fail? ()
  (format t "Do I fail?~%"))

(eval-when (:compile-toplevel)
  (format t "At compilation-time: ") (foo-dispatch "fail?"))

(eval-when (:load-toplevel)
  (format t "At load-time: ") (foo-dispatch "fail?"))

(eval-when (:execute)
  (format t "At run-time: ") (foo-dispatch "fail?"))


* (compile-file "foo.lisp")

; compiling file "/tmp/foo.lisp" (written 10 JUL 2006 12:30:36 PM):
; compiling (DEFVAR *FOO-FUNCTIONS* ...)
; compiling (DEFMACRO DEF-FOO-FUNCTION ...)
; compiling (DEFUN FOO-DISPATCH ...)
; compiling (DEF-FOO-FUNCTION HELLO ...)
; compiling (DEF-FOO-FUNCTION FAIL? ...)At compilation-time: Unknown function: "fail?"
usage: ...whatever...blah...blah...
; compiling (FORMAT T ...)
; compiling (FOO-DISPATCH "fail?")

; /tmp/foo.fasl written
; compilation finished in 0:00:00
#P"/tmp/foo.fasl"
NIL
NIL
*  (FOO-DISPATCH "fail?")
Unknown function: "fail?"
usage: ...whatever...blah...blah...
NIL
* (sb-ext:quit)


[···@thalassa tmp]$ sbcl

#<PACKAGE "COMMON-LISP-USER"> 
;; Reading ASDF packages from /home/pjb/asdf-central-registry.data...
; loading system definition from
; /usr/local/languages/sbcl/lib/sbcl/sb-bsd-sockets/sb-bsd-sockets.asd into
; #<PACKAGE "ASDF0">
; registering #<SYSTEM SB-BSD-SOCKETS {AD01A99}> as SB-BSD-SOCKETS
; registering #<SYSTEM SB-BSD-SOCKETS-TESTS {B089471}> as SB-BSD-SOCKETS-TESTS
; loading system definition from
; /usr/local/languages/sbcl/lib/sbcl/sb-posix/sb-posix.asd into
; #<PACKAGE "ASDF0">
; registering #<SYSTEM SB-POSIX {A8F7F71}> as SB-POSIX
; registering #<SYSTEM SB-POSIX-TESTS {AA7F4E1}> as SB-POSIX-TESTS
~/.sbclrc loaded
* (load"foo.fasl")
At load-time: Do I fail?
T
*  (FOO-DISPATCH "fail?")
Do I fail?
NIL
* (sb-ext:quit)
[···@thalassa tmp]$ 

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Kitty like plastic.
Confuses for litter box.
Don't leave tarp around.
From: Sascha Wilde
Subject: Re: Idiom to call function from string
Date: 
Message-ID: <4hhu8gF1rncmpU1@individual.net>
····@rpw3.org (Rob Warnock) wrote:

> Sascha Wilde  <·····@sha-bang.de> wrote:
[...]
> | (funcall (find-symbol (string-upcase (concatenate 'string 
> |                                                   "foo-" "bar")) 
> |                       :baz))
[...]
> From your description, I'm assuming that the "bar" is coming
> from external user input, and the "foo-" is a prefix you use
> in your application to distinguish functions which may be called
> from such external input.

yes

> If that's the case, you might want to collect all the names of all
> the "foo-" functions into a hash table[1], whereupon the above call
> turns into:
>
>     (funcall (gethash "bar" *foo-functions*))

This approach is indeed much nicer.  My primary motivation wasn't to
solve a concrete problem, but to play around with lisp and figure out
how to create the name of a function to call at run time.

From the answers in this thread I learned that
- the way I did it wasn't that bad
- _but_ in most cases it's best not to do it at all... (as there are
  much better solutions).

thanks!
sascha
-- 
Sascha Wilde
To become a Jedi, use Emacs you have to.
From: Thomas A. Russ
Subject: Re: Idiom to call function from string
Date: 
Message-ID: <ymibqrx1jb3.fsf@sevak.isi.edu>
Sascha Wilde <·····@sha-bang.de> writes:

> I want to call an existing function after construction it's name from
> strings.  I came up with:
> 
> (funcall (find-symbol (string-upcase (concatenate 'string 
>                                                   "foo-" "bar")) 
>                       :baz))
> 
> to call function FOO-BAR from package BAZ, which actually works, but
> I'm under the impression that that's not very elegant -- so my
> question is: is there a standard idom to do this?

Not really.

That is because normally one doesn't really try to build function names
from strings at run time.  There may be circumstances where this needs
to be done, but it isn't very common.

Normally one tries to work at the symbol level for lisp code rather than
manipulating strings.

That said, your solution is one reasonable solution to the problem as
stated.  The only real alternatives are

(1) use INTERN instead of FIND-SYMBOL.  Probably not as good for this
    application, since INTERN will create symbols if they don't already
    exist, and any newly created symbol won't have a function
    definition, so getting NIL back is probably more useful.

(2) use READ-FROM-STRING instead of FIND-SYMBOL.  This frees you from
    having to worry about the string-upcasing, using the Lisp reader
    to do it for you.  Using explicit upcasing when you know (because
    you've written the functions) that the names are all uppercase is
    safer.  Also you don't have to worry about READ-EVAL
    vulnerabilities. 

(3) use format to build the symbol name.  I personally like this, but
    it is likely to be a bit less efficient, but can be more succinct
    especially if you have a more general pattern:
    (format nil ··@:(~A~A~)" "foo-" "bar")
    (format nil ··@:(~A-~A~)" "foo" "bar")
    (format nil ··@:(~{~A~^-~}~)" '("foo" "bar" "and" "even" "more"))


-- 
Thomas A. Russ,  USC/Information Sciences Institute