From: Ruhi Bloodworth
Subject: loading and calling a function at runtime
Date: 
Message-ID: <slrnb3k8ee.5br.ruhi@colophon.cjb.net>
Is there a way to call a function defined in another file, without
adding it to the current lisp image's top level environment ?

(defun bar ()
  (load "test.fasl")
  (foo 12))

(bar)
;;; foo now exists at the top level

Regards,
Ruhi Bloodworth

From: Pascal Bourguignon
Subject: Re: loading and calling a function at runtime
Date: 
Message-ID: <87adhh1we5.fsf@thalassa.informatimago.com>
Ruhi Bloodworth <····@colophon.cjb.net> writes:

> Is there a way to call a function defined in another file, without
> adding it to the current lisp image's top level environment ?
> 
> (defun bar ()
>   (load "test.fasl")
>   (foo 12))
> 
> (bar)
> ;;; foo now exists at the top level
> 
> Regards,
> Ruhi Bloodworth

- Implement your  own lisp in lisp and  load the file in  this lisp in
  lisp environment.

- use packages!   Then you can  delete the whole package.   Of course,
  the file  contains its own  package definition and  IN-PACKAGE call,
  etc, you'd have to filter that (there is no notion of sub-package in
  Common-Lisp), but it does not seems the case since you call (foo 12)
  directly.


[48]> (DEFUN BAR ()
  (LET* ((PACK-NAME (SYMBOL-NAME (GENSYM "TEMP-PACK")))
         (PACK (MAKE-PACKAGE PACK-NAME :USE '("COMMON-LISP")))
         (OLD-PACKAGE *PACKAGE*))
    (LET ((*PACKAGE* PACK))
      (LOAD "foo")
      (FUNCALL (INTERN "FOO" PACK) 12))
    (DELETE-PACKAGE PACK)))
BAR
[49]> (PROGN
 (WITH-OPEN-FILE (FOO "foo.lisp" :DIRECTION :OUTPUT 
                      :IF-EXISTS :OVERWRITE 
                      :IF-DOES-NOT-EXIST :CREATE)
   (FORMAT FOO "(DEFUN FOO (N) (FORMAT T \"~~&In FOO, N = ~~W~~%\" N))~%"))
 (LET ((OLDPS (COPY-SEQ (LIST-ALL-PACKAGES))))
   (BAR)
   (EQUAL OLDPS (LIST-ALL-PACKAGES))))
In FOO, N = 12
T
[50]> (FOO 42)
*** - EVAL: the function FOO is undefined



        

-- 
__Pascal_Bourguignon__                   http://www.informatimago.com/
----------------------------------------------------------------------
There is a fault in reality. Do not adjust your minds. -- Salman Rushdie
From: Erann Gat
Subject: Re: loading and calling a function at runtime
Date: 
Message-ID: <gat-3101031533170001@k-137-79-50-101.jpl.nasa.gov>
In article <···················@colophon.cjb.net>, Ruhi Bloodworth
<····@colophon.cjb.net> wrote:

> Is there a way to call a function defined in another file, without
> adding it to the current lisp image's top level environment ?

Yes, this can be done.  However, your example seems to indicate that this
is not what you want:

> (defun bar ()
>   (load "test.fasl")
>   (foo 12))
> 
> (bar)
> ;;; foo now exists at the top level

And the presumption is that this is bad.  But you seem to want to call the
function you just loaded by referring to it as if it were defined in the
top level environment.  So if, as you say you want to do, you do not
define the function in the top-level environment then calling FOO will
result in an error.

I presume what you really want is something like this:

(defun bar ()
  (let ( (foo (load-function-from-file "test.fasl")) )
    (funcall foo ...)))

or

(defun foo ()
  (flet-from-file ( (foo "test.fasl") )
    (foo ...)))

or even

(defun foo ()
  (with-local-functions-from-file "test.fasl"
    (foo ...))  ; Calls the FOO defined in test.fasl
  (foo ...))    ; Calls the global FOO (if there is one)

All these can be done, though it's a little awkward.  (And the last one is
particularly awkward and error-prone, since the local functions cannot be
lexically scoped.)  Confirm that this is what you want and I'll explain
how to do it (assuming you haven't already figured it out from this
description.)

E.
From: Ruhi Bloodworth
Subject: Re: loading and calling a function at runtime
Date: 
Message-ID: <slrnb3mahn.64m.ruhi@colophon.cjb.net>
> And the presumption is that this is bad.  But you seem to want to call the
> function you just loaded by referring to it as if it were defined in the
> top level environment.  So if, as you say you want to do, you do not
> define the function in the top-level environment then calling FOO will
> result in an error.
> 
> I presume what you really want is something like this:
> 
> (defun bar ()
>   (let ( (foo (load-function-from-file "test.fasl")) )
>     (funcall foo ...)))
> 
> or
> 
> (defun foo ()
>   (flet-from-file ( (foo "test.fasl") )
>     (foo ...)))
> 
> or even
> 
> (defun foo ()
>   (with-local-functions-from-file "test.fasl"
>     (foo ...))  ; Calls the FOO defined in test.fasl
>   (foo ...))    ; Calls the global FOO (if there is one)
> 
> All these can be done, though it's a little awkward.  (And the last one is
> particularly awkward and error-prone, since the local functions cannot be
> lexically scoped.)  Confirm that this is what you want and I'll explain
> how to do it (assuming you haven't already figured it out from this
> description.)
> 
> E.

I think want to do something like either of the first two options. Though
Pascal's solution of using packages seems very workable as does Marco's
of using fmakunbound.

I decided to learn Lisp by creating a version of the BRL web template
language using Common Lisp Instead of scheme. Currently the system
translates the template file into a function that when called with the
appropriate arguments will render the web page and saves it to a .fasl
file.

I can implement load-function-from-file using read if it is a text file,
but don't know how to do it if the file is compiled.

Regards,
Ruhi
From: Erann Gat
Subject: Re: loading and calling a function at runtime
Date: 
Message-ID: <gat-0102030911000001@192.168.1.51>
In article <···················@colophon.cjb.net>, Ruhi Bloodworth
<····@colophon.cjb.net> wrote:

> I can implement load-function-from-file using read if it is a text file,
> but don't know how to do it if the file is compiled.

The trick is to realize that you can compile a file containing any Lisp
forms, not just DEFUNs, and those forms will be executed when the file is
loaded.  So you can put something like:

(store-in-some-canonical-place (lambda () ...)))

in the file and compile it.  When you load the resulting .fasl file, the
function will be stored in some canonical place, where
load-function-from-file can retrieve it.

E.
From: Christopher C. Stacy
Subject: Re: loading and calling a function at runtime
Date: 
Message-ID: <uvg050wty.fsf@dtpq.com>
>>>>> On Fri, 31 Jan 2003 07:12:15 GMT, Ruhi Bloodworth ("Ruhi") writes:
 Ruhi> Is there a way to call a function defined in another file, without
 Ruhi> adding it to the current lisp image's top level environment ?

I am not sure I understand your question, but 
probably the answer you're looking for is: no.

 Ruhi> (defun bar ()
 Ruhi>   (load "test.fasl")
 Ruhi>   (foo 12))

I am not sure what you mean by "top level environment".

When Lisp reads the above code (eg. you typed it in, 
or loaded it from a file), it will see that you have 
referenced a symbol FOO.  When what you have read is
evaluated (which happens right after it is read), 
the function BAR will be defined.  

If you are compiling this code, the compiler will now 
warn you about the undefined function FOO.

Of course, if you had previously defined the function FOO
(by loading that other file containing the definition),
then you would get no warning.  But I guess you wouldn't
be asking the question, in that case.

 Ruhi> (bar)
 Ruhi> ;;; foo now exists at the top level

I don't know what you mean by "foo now exists".

Calling the function BAR in your example will not cause a
function FOO to come into existence.  A symbol named FOO
had already existed ever since BAR was read in, but since
there is no function associated with the symbol, your
program will blow up with an "undefined function" error.

You cannot call a function that does not exist.
You can make forward references to functions that do not exist.
The compiler will warn you about these functions.

Merely entering a symbol such as FOO will "intern" (create) the symbol,
but that action alone does not create a function or a variable.
From: Barry Margolin
Subject: Re: loading and calling a function at runtime
Date: 
Message-ID: <EsD_9.30$is4.1635@paloalto-snr1.gtei.net>
In article <·············@dtpq.com>,
Christopher C. Stacy <······@dtpq.com> wrote:
>>>>>> On Fri, 31 Jan 2003 07:12:15 GMT, Ruhi Bloodworth ("Ruhi") writes:
> Ruhi> Is there a way to call a function defined in another file, without
> Ruhi> adding it to the current lisp image's top level environment ?
>
>I am not sure I understand your question, but 
>probably the answer you're looking for is: no.
>
> Ruhi> (defun bar ()
> Ruhi>   (load "test.fasl")
> Ruhi>   (foo 12))
>
>I am not sure what you mean by "top level environment".
>
>When Lisp reads the above code (eg. you typed it in, 
>or loaded it from a file), it will see that you have 
>referenced a symbol FOO.  When what you have read is
>evaluated (which happens right after it is read), 
>the function BAR will be defined.  
>
>If you are compiling this code, the compiler will now 
>warn you about the undefined function FOO.
>
>Of course, if you had previously defined the function FOO
>(by loading that other file containing the definition),
>then you would get no warning.  But I guess you wouldn't
>be asking the question, in that case.
>
> Ruhi> (bar)
> Ruhi> ;;; foo now exists at the top level
>
>I don't know what you mean by "foo now exists".
>
>Calling the function BAR in your example will not cause a
>function FOO to come into existence.  A symbol named FOO
>had already existed ever since BAR was read in, but since
>there is no function associated with the symbol, your
>program will blow up with an "undefined function" error.

I think you were supposed to infer that test.fasl contains a definition of
FOO.  Calling BAR will load the file, causing the function to come into
existence.

I suspect what he's looking for is a way to load the function and have it
define a local function (like FLET and LABELS do).  I don't think there's
any way to do that.

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Christopher C. Stacy
Subject: Re: loading and calling a function at runtime
Date: 
Message-ID: <ur8as286p.fsf@dtpq.com>
>>>>> On Fri, 31 Jan 2003 22:38:02 GMT, Christopher C Stacy ("Christopher") writes:
 Ruhi> (defun bar ()
 Ruhi> (load "test.fasl")
 Ruhi> (foo 12))

I just realized that maybe you meant that the file "test.fasl"
contains the definition for the function FOO. Everything in my
previous message is still important to understanding your problem.
If FOO is defined in "test.fasl", then you will still get a 
compiler warning about FOO being undefined.  The first time you
call the function BAR, the LOAD function will bring FOO into existence.
Then your program execution will not blow up with an undefined function error.

But it's not a good idea to do it that way; your program should be
written so that everything compiles without errors.  You don't want
the function BAR to have a "Undefined Function FOO" error.

So maybe what you're asking is how to write your code so that you 
can call functions that will be loaded into the application later.

If you compile all the files as a unit,this would not be an issue.
But suppose that the function definitions will really not be 
available until run-time.

I would suggest defining a dummy function up front:

(defmacro defun-later (name)
  `(defun ,name (&rest args)
     (declare (ignore args))
     (not-yet-defined ',name)))

(defun not-yet-defined (name)
  (error "The function ~S was called, but has not been defined yet." 
         name))

(defun-later foo)

Then your example BAR would compile without errors, and when BAR is
actually called, the dummy definition will be replaced by the real
definition of FOO in "test.fasl.

If you want to get fancier, you could have your function load itself!
The definition below also has the advantage that the compiler can do
argument list congruency when compiling the call to FOO.

(defmacro defun-autoload (name (args) filename &key verbose print)
  `(progn
     (eval-when (:load-toplevel :compile-toplevel :execute)
       (when (and (fboundp ',name)
                  (not (get ',name 'autoload-filename)))
         (warn "The function ~A is being defined for autoloading, but it already has a definition." 
               ',name))
       (setf (get ',name 'autoload-filename) ,filename))
     (defun ,name (,args)
       (let ((this (symbol-function ',name))
             (new nil)
             (filename (get ',name 'autoload-filename)))
         (load filename :verbose ,verbose :print ,print)
         (setq new (symbol-function ',name))
         (cond ((eq this new)
                (error "The function ~S was called, but is not defined in ~A"
                       ',name filename))
               (t
                (setf (get ',name 'autoload-filename) nil)
                (,name ,args)))))))


(defun-autoload bar (i) "autoload-bar" :print t :verbose t)

An old dialect called MACLISP used to have the "autoload" feature in
the language, but with Common Lisp you have to write it yourself,
something like the above.

Chris
From: Duane Rettig
Subject: Re: loading and calling a function at runtime
Date: 
Message-ID: <44r7olqxn.fsf@beta.franz.com>
······@dtpq.com (Christopher C. Stacy) writes:

> An old dialect called MACLISP used to have the "autoload" feature in
> the language, but with Common Lisp you have to write it yourself,
> something like the above.

Unless, as an extension, your CL implementation already has it:

CL-USER(1): (apropos "DEF-AUTOLOAD")
EXCL::DEF-AUTOLOAD-FUNCTION [macro] (NAME FILE)
EXCL::DEF-AUTOLOAD-GENERIC-FUNCTION [macro] (NAME FILE FORMALS ACTUALS)
EXCL::DEF-AUTOLOAD-MACRO [macro] (NAME FILE)
CL-USER(2): 

I suppose we should clean these up, and then export and document them...

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Kent M Pitman
Subject: Re: loading and calling a function at runtime
Date: 
Message-ID: <sfwwukkhiku.fsf@shell01.TheWorld.com>
Ruhi Bloodworth <····@colophon.cjb.net> writes:

> Is there a way to call a function defined in another file, without
> adding it to the current lisp image's top level environment ?
> 
> (defun bar ()
>   (load "test.fasl")
>   (foo 12))
> 
> (bar)
> ;;; foo now exists at the top level


Sure.  You're asking for dynamic behavior.  Use dynamic (i.e., special
variables).

========================================================================
 foo.lisp
========================================================================

(in-package "CL-USER")

(declaim (special *bar*))

(defun foo ()
  (let (*bar*)
    (load "bar")
    (funcall *bar*)))

========================================================================
 bar.lisp
========================================================================

(in-package "CL-USER")

(declaim (special *bar*))

(setq *bar* #'(lambda () (format t "~&BAR facility used.~%")))

========================================================================