From: Iban Hatchondo
Subject: method and function overloading/redefinition
Date: 
Message-ID: <ba2kss$r2r$1@news.u-bordeaux.fr>
I recently stumbled on a problem that prompted me to create an
interface for defining and undefining functions and methods.  Here is
the situation: in the Eclipse window manager (1) I have an interface
for themes.  It is possible to define, overload, and redefine methods
and function in the eclipse-internal package.  When I want to switch
from one theme to another, I would like to undefine all the functions
and methods that were defined as part of the theme.  For that purpose,
I wrote this little interface to permit exactly that.

I would like to have some feedback on this design, please.  Does it
look reasonable?

Thanks in advance,
Iban.

1 - (http://nittin.net/eclipse/download.shtml)

;;;;
;; Small mop tools that allow the user to define/overload/redefine 
methods and
;; functions inside his theme definition file with the insurence that 
when his
;; theme will be "unloaded" properly.

(defvar *old-lambdas* ())
(defvar *new-lambdas* ())

(defgeneric remove-definition (generic-definition definition)
   (:documentation "undefine lambda expression"))

(defgeneric add-definition (generic-definition definition)
   (:documentation "define lambda expression"))

(defun save-old-lambda (generic-definition lambda-def)
   (push (cons generic-definition lambda-def) *old-lambdas*))

(defun save-new-lambda (generic-definition lambda-def)
   (push (cons generic-definition lambda-def) *new-lambdas*))

(defmethod remove-definition ((generic-definition symbol) lambda)
   (fmakunbound lambda))

(defmethod remove-definition ((generic-definition generic-function) method)
   (remove-method generic-definition method))

(defmethod add-definition ((generic-definition symbol) lambda)
   (setf (symbol-function generic-definition) lambda))

(defmethod add-definition ((generic-definition generic-function) method)
   (add-method generic-definition method))

(defun parse-theme-defmethod (form)
   (declare (list form))
   (let ((name (pop form))
	(qualifiers ())
	(specialized-lambda-list ()))
     (loop (if (and (car form) (atom (car form)))
	      (push (pop form) qualifiers)
	      (return (setq qualifiers (nreverse qualifiers)))))
     (setq specialized-lambda-list (pop form))
     (values name qualifiers specialized-lambda-list form)))

;; Public.
(defun rollback-theme-def* ()
   (loop for (generic-definition . lambda-def) in *new-lambdas*
	do (remove-definition generic-definition lambda-def))
   (loop for (generic-definition . lambda-def) in *old-lambdas*
	do (add-definition generic-definition lambda-def))
   (setf *old-lambdas* ()
	*new-lambdas* ())
   (values))

;; Public.
(defmacro theme-defun (&rest forms)
     "Use like defun (defun foo ...).
Save precedant function definition if it exists.
Define and save the new one."
     (let ((name (pop forms))
	  (old-fun (gensym))
	  (new-fun (gensym)))
       `(let ((,old-fun (and (fboundp ',name) (fdefinition ',name))))
	 (when ,old-fun
	   (save-old-lambda ',name ,old-fun)
	   (fmakunbound ',name))
	 (let ((,new-fun (defun ,name ,@forms)))
	   (save-new-lambda ',name ,new-fun)
	   ,new-fun))))

;; Public.
(defmacro theme-defmethod (&rest forms)
   "Use like defmethod (defmethod foo ...) (defmethod (setf foo) ...).
Save precedant method definition if it exists.
Define and save the new one."
   (multiple-value-bind (name qualifiers lambda-list body)
       (parse-theme-defmethod forms)
     (let ((generic-definition (gensym))
	  (old-m (gensym))
	  (new-m (gensym)))
       `(let ((,generic-definition (and (fboundp ',name) (fdefinition 
',name)))
	     (,old-m nil))
	 (when ,generic-definition
	   (setf ,old-m
		 (find-method
		     ,generic-definition
		     ',qualifiers
		     (mapcar #'(lambda (s) (if (consp s) s (find-class s)))
			     ',(loop for specializer in lambda-list
				     if (listp specializer)
				     collect (second specializer)
				     else collect t))
		     nil #| don't report an error |#)))
	 (let ((,new-m (defmethod ,name ,@qualifiers ,lambda-list ,@body)))
	   (when ,old-m
	     (save-old-lambda ,generic-definition ,old-m))
	   (unless ,generic-definition
	     (setf ,generic-definition (fdefinition ',name)))
	   (save-new-lambda ,generic-definition ,new-m)
	   ,new-m)))))

From: Daniel Barlow
Subject: Re: method and function overloading/redefinition
Date: 
Message-ID: <874r3vhyj7.fsf@noetbook.telent.net>
Iban Hatchondo <········@labri.fr> writes:

> I recently stumbled on a problem that prompted me to create an
> interface for defining and undefining functions and methods.  Here is
> the situation: in the Eclipse window manager (1) I have an interface
> for themes.  It is possible to define, overload, and redefine methods
> and function in the eclipse-internal package.  When I want to switch
> from one theme to another, I would like to undefine all the functions
> and methods that were defined as part of the theme.  For that purpose,
> I wrote this little interface to permit exactly that.

Is this necessary?  It sounds complex.

Why not make all the theme-related methods specialise on the theme
itself (if there's no class fvor a theme, you could use EQL
specialisers on the theme name as a keyword) - then you can have
several themes loaded concurrently without them interfering with each
other.  This probably doesn't impact terrifically on the size of the
application (by comparsion with the 20Mb of CMUCL core you get for
free, anyway) and keeps things a lot simpler.

If you then additionally arrange for themes to be selected per-window
instead of globally, it would make it much simpler for example to
implement a "preview theme" window, or for theme developers to test
their theme while developing it, or even just for silly pictures
that have multiple window themes on the same screen.  See
<http://scwm.sourceforge.net/scwm-screenshot.gif> - not a composite
image


-dan

-- 

   http://www.cliki.net/ - Link farm for free CL-on-Unix resources 
From: Iban Hatchondo
Subject: Re: method and function overloading/redefinition
Date: 
Message-ID: <ba2qq8$tbh$1@news.u-bordeaux.fr>
Daniel Barlow wrote:
> Iban Hatchondo <········@labri.fr> writes:
> 
> 
>>I recently stumbled on a problem that prompted me to create an
>>interface for defining and undefining functions and methods.  Here is
>>the situation: in the Eclipse window manager (1) I have an interface
>>for themes.  It is possible to define, overload, and redefine methods
>>and function in the eclipse-internal package.  When I want to switch
>>from one theme to another, I would like to undefine all the functions
>>and methods that were defined as part of the theme.  For that purpose,
>>I wrote this little interface to permit exactly that.
> 
> 
> Is this necessary?  It sounds complex.
> 
> Why not make all the theme-related methods specialise on the theme
> itself (if there's no class fvor a theme, you could use EQL
> specialisers on the theme name as a keyword) - then you can have
> several themes loaded concurrently without them interfering with each
> other.  This probably doesn't impact terrifically on the size of the
> application (by comparsion with the 20Mb of CMUCL core you get for
> free, anyway) and keeps things a lot simpler.

Totally true, (it is on my todo list), but still, what happend if some 
theme desiners needs more ? As replacing one the core input method of 
eclipse ? What should I do in that case ? Shall I provide a mechanism 
for them to roll back or shall I simply forbide such possibilities ? I 
don't really know.

Iban.
From: Kent M Pitman
Subject: Re: method and function overloading/redefinition
Date: 
Message-ID: <sfw8yt7566e.fsf@shell01.TheWorld.com>
Iban Hatchondo <········@labri.fr> writes:

> Daniel Barlow wrote:
> > Iban Hatchondo <········@labri.fr> writes:
> >
> >> I recently stumbled on a problem that prompted me to create
> >> an interface for defining and undefining functions and
> >> methods. [...]
> >
> > Is this necessary?  It sounds complex. Why not make all the
> > theme-related methods specialise on the theme [...]
> 
> Totally true, (it is on my todo list), but still, what happend if some
> theme desiners needs more ?

Then have them define a new theme.  They can do this by redefining the 
class, or by making a class with a new name, or by making a new package
and making in the new package a class of the same name, or by deleting the
package and remaking it and making a new class with the same name in the
remade package.  Any of these is logically equivalent to having deleted
the methods and functions, so I don't see how if your first solution worked,
Daniel's solution would be any worse.