From: JP Massar
Subject: Compiling methods on the fly
Date: 
Message-ID: <uhd0m0pfhn1842fqliqc8diqi678vuij57@4ax.com>
If I had a program that needed to create functions and compile them at
run-time I could do something like

(defun create-function (name args body-forms)
  (compile (eval `(defun ,name ,args ,@body-forms))))
 
> (create-function 'bar '(y) '((1- y)))
BAR
NIL
NIL

 > (compiled-function-p (symbol-function 'bar))
T

I could do a similar thing if I wanted to create and compile named
macros at run time.


But is there any way (short of writing the definition of a method to a
file and calling COMPILE-FILE and then LOAD) of creating a new method
definition on-the-fly at execution time and insuring that the code
that runs the method gets compiled?

Thanks.

From: Edi Weitz
Subject: Re: Compiling methods on the fly
Date: 
Message-ID: <87llensm13.fsf@miles.agharta.de>
On Sun, 03 Oct 2004 17:32:52 GMT, JP Massar <······@alum.mit.edu> wrote:

> If I had a program that needed to create functions and compile them
> at run-time I could do something like
>
> (defun create-function (name args body-forms)
>   (compile (eval `(defun ,name ,args ,@body-forms))))
>  
>> (create-function 'bar '(y) '((1- y)))
> BAR
> NIL
> NIL
>
>  > (compiled-function-p (symbol-function 'bar))
> T

That's not strictly portable, BTW - see

  <http://groups.google.com/groups?threadm=m3ofgpdkgn.fsf%40dyn138.dbdmedia.de>

> I could do a similar thing if I wanted to create and compile named
> macros at run time.
>
> But is there any way (short of writing the definition of a method to
> a file and calling COMPILE-FILE and then LOAD) of creating a new
> method definition on-the-fly at execution time and insuring that the
> code that runs the method gets compiled?

Use the MOP, ADD-METHOD. See

  <http://article.gmane.org/gmane.lisp.lispworks.general/2757>

and follow-ups for an example.

Cheers,
Edi.

-- 

"Lisp doesn't look any deader than usual to me."
(David Thornley, reply to a question older than most languages)

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: JP Massar
Subject: Re: Compiling methods on the fly
Date: 
Message-ID: <gli0m0d9g5mi00j3fh51r7jaaemh1n2pq5@4ax.com>
On Sun, 03 Oct 2004 20:18:32 +0200, Edi Weitz <········@agharta.de> w 
>
>Use the MOP, ADD-METHOD. See
>
>  <http://article.gmane.org/gmane.lisp.lispworks.general/2757>
>
>and follow-ups for an example.
>
 
So there's no way to do this within ANSI Common Lisp since I'd have
to create an instance of STANDARD-METHOD with a compiled :function
slot value, but STANDARD-METHOD is not specified as to what to give
MAKE-INSTANCE so as to create it within the ANSI spec?
From: Thomas A. Russ
Subject: Re: Compiling methods on the fly
Date: 
Message-ID: <ymism8ua1ud.fsf@sevak.isi.edu>
JP Massar <······@alum.mit.edu> writes:

> So there's no way to do this within ANSI Common Lisp since I'd have
> to create an instance of STANDARD-METHOD with a compiled :function
> slot value, but STANDARD-METHOD is not specified as to what to give
> MAKE-INSTANCE so as to create it within the ANSI spec?

Correct.  When we went through this exercise in Loom many years ago, we
pretty much ended up with special case code for every Lisp system that
was supported.  The final result was the following code set of code.
Note that his is a bit specialized, since we only needed to create
methods that took a single argument.  (You may also note that there was
one case where we just gave up and used EVAL...)


#-(or :lucid :ti :mcl :aclpc :cmu18)
;; NEW, Meta-Object Protocol compliant:
(defun add-unary-method (methodName className lambdaExpression)
  ;; Create a method with name "methodName" for the class named "className",
  ;;    where "lambdaExpression" defines its parameter and body;
  ;; "lambdaExpression" may be the name of a Lisp function;
  (CLOS::ensure-generic-function methodName :lambda-list '(self))
  (let ((newMethod (make-instance 'CLOS::STANDARD-METHOD
                     :lambda-list (cadr lambdaExpression)
                     :specializers (list (CLOS::find-class className))
                     :function (compile nil lambdaExpression))))
    (CLOS::add-method (symbol-function methodName) newMethod)
    newMethod ))

#+(or :MCL :lucid)
;; Works in MCL 2.0, Lucid 4.0, ?
(defun add-unary-method (methodName className lambdaExpression)
  ;; Create a method with name "methodName" for the class named "className",
  ;;    where "lambdaExpression" defines its parameter and body;
  ;; "lambdaExpression" may be the name of a Lisp function;
  (CLOS::ensure-generic-function methodName :lambda-list '(self))
  (let ((newMethod (make-instance 'CLOS::STANDARD-METHOD)))
    (setf (slot-value newMethod 'CLOS::specializers) 
          (list (CLOS::find-class className)))
    (setf (slot-value newMethod 'CLOS::function)
          (compile nil lambdaExpression))
    #-:MCL (setf (slot-value newMethod 'CLOS::lambda-list)
		 (second lambdaExpression))
    #+:MCL (setf (slot-value newMethod 'CLOS::name) methodName)
    (CLOS::add-method (symbol-function methodName) newMethod)
    newMethod ))

#+:ACLPC
(defun add-unary-method (methodName className lambdaExpression)
  ;; Create a method with name "methodName" for the class named "className",
  ;;    where "lambdaExpression" defines its parameter and body;
  ;; "lambdaExpression" may be the name of a Lisp function;
   (eval `(defmethod ,methodName ((,(caadr lambdaExpression) ,className))
             ,@(cddr lambdaExpression))))

#+:TI
(defun add-unary-method (methodName className lambdaExpression)
  ;; Create a method with name "methodName" for the class named
  ;;    "className", where "lambdaExpression" defines its
  ;;    parameter and body;
  ;; "lambdaExpression" may be the name of a Lisp function;
  (CLOS::ensure-generic-function methodName :lambda-list '(self))
  (let ((newMethod (make-instance 'CLOS::STANDARD-METHOD)))
    (setf (slot-value newMethod 'CLOS::parameter-specializers) 
          (list (CLOS::find-class className)))
    (setf (slot-value newMethod 'TICLOS::qualifiers) nil)
    (setf (slot-value newMethod 'TICLOS::arglist-description) '(1 0))
    (setf (slot-value newMethod 'CLOS::function)
          (compile nil lambdaExpression))
    (CLOS::add-method (symbol-function methodName) newMethod)
    newMethod ))

 ;; Should this be :cmu17 ?
#+:cmu18
(defun add-unary-method (methodName className lambdaExpression)
  ;; Create a method with name "methodName" for the class named "className",
  ;;    where "lambdaExpression" defines its parameter and body;
  ;; "lambdaExpression" may be the name of a Lisp function?;
  ;; Note: current MOP functions work on PCL's version of the class
  ;; system, not lisp' parallel versions.
  ;; The :function arg to make-instance is a function of two args,
  ;;     the first arg is a list of the args to pass to the function,
  ;;     the second arg is a list of next-methods. MAKE-METHOD-LAMBDA
  ;;     is MOP's way of generating such a function that works.
  (ensure-generic-function methodName :lambda-list '(self))
  (let* ((proto-gf (symbol-function methodName))
	 (proto-me (MOP:class-prototype (find-class 'standard-method)))
	 (class-sp (MOP:class-of (MOP:class-prototype (find-class className))))
	 (method-function-lambda
	  (MOP:make-method-lambda proto-gf proto-me lambdaExpression nil))
	 (newMethod (make-instance (MOP:class-of proto-me) ; s-g-f
		      :lambda-list (cadr lambdaExpression)
		      :specializers (list class-sp)
		      :function (compile nil method-function-lambda))))
    (add-method (symbol-function methodName) newMethod)
    newMethod ))





-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Marco Baringer
Subject: Re: Compiling methods on the fly
Date: 
Message-ID: <m2k6u7o3qa.fsf@bese.it>
JP Massar <······@alum.mit.edu> writes:

> If I had a program that needed to create functions and compile them at
> run-time I could do something like
>
> (defun create-function (name args body-forms)
>   (compile (eval `(defun ,name ,args ,@body-forms))))

what's wrong with:

(defun create-method (name qualifiers args body)
  (compile (eval `(defmethod ,name ,@qualifiers ,args ,@body))))

this is, more or less, exactly what most IDEs do every time you hit
C-M-x.

-- 
-Marco
Ring the bells that still can ring.
Forget your perfect offering.
There is a crack in everything.
That's how the light gets in.
     -Leonard Cohen
From: JP Massar
Subject: Re: Compiling methods on the fly
Date: 
Message-ID: <56v0m0hhhj6792o8f9unkkvuucpdv0rhc9@4ax.com>
On Mon, 04 Oct 2004 00:07:25 +0200, "Marco Baringer" <··@bese.it>
wrote:

>JP Massar <······@alum.mit.edu> writes:
>
>> If I had a program that needed to create functions and compile them at
>> run-time I could do something like
>>
>> (defun create-function (name args body-forms)
>>   (compile (eval `(defun ,name ,args ,@body-forms))))
>
>what's wrong with:
>
>(defun create-method (name qualifiers args body)
>  (compile (eval `(defmethod ,name ,@qualifiers ,args ,@body))))
>

Lispworks
-----------
 
  (compile (eval '(defmethod fred ((x fixnum)) (1+ x))))

Error: #<STANDARD-METHOD FRED NIL (FIXNUM) 20604B54> is neither of
type SYMBOL nor a list of the form (SETF SYMBOL).


Allegro
--------

 (compile (eval '(defmethod fred ((x fixnum)) (1+ x))))
; While compiling #<STANDARD-METHOD FRED (FIXNUM)>:
Error: `#<STANDARD-METHOD FRED (FIXNUM)>' is not fbound
[condition type: UNDEFINED-FUNCTION]


What Lisp are you running on that this works for?
From: Steven M. Haflich
Subject: Re: Compiling methods on the fly
Date: 
Message-ID: <41608AC8.8020208@alum.mit.edu>
Marco Baringer wrote:

> JP Massar <······@alum.mit.edu> writes:
> 
> (defun create-method (name qualifiers args body)
>   (compile (eval `(defmethod ,name ,@qualifiers ,args ,@body))))

This won't work at all.  Execution of defmethod returns a method
object which is necessarily not a function.

What you need to do is create a method function which can be compiled
just like any other function and then made the method-function of
a method object.  Creating a method function requires use of the MOP,
specifically, make-method-lambda.

The practical problem is that, at least a couple years ago when Ray
de Lacaze surveyed available implementations, he found none that
implemented make-method-lambda with even approximate correctness.

I believe Allegro supports a function spec syntax for method functions,
so if you have an interpreted method (that isn't a closure) you can
compile it with something like

   (compile '(method foo :after (symbol t)))

but this sort of function name access isn't portable.
From: Nicolas Neuss
Subject: Re: Compiling methods on the fly
Date: 
Message-ID: <877jq6oo0e.fsf@ortler.iwr.uni-heidelberg.de>
JP Massar <······@alum.mit.edu> writes:

> But is there any way (short of writing the definition of a method to a
> file and calling COMPILE-FILE and then LOAD) of creating a new method
> definition on-the-fly at execution time and insuring that the code
> that runs the method gets compiled?
>
> Thanks.

I'm using "(funcall (compile nil (lambda () (defmethod ...))))".

Yours, Nicolas.