Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!tut.cis.ohio-state.edu!ucbvax!agate!bionet!arisia!roo!masinter From: masinter@parc.xerox.com (Larry Masinter) Newsgroups: comp.lang.lisp Subject: Re: Lisp 1.5 functional values as objects Message-ID: Date: 10 Oct 90 07:08:23 GMT References: <1950001@hpgnd.HP.COM> Sender: news@parc.xerox.com Organization: Xerox PARC, Palo Alto, CA Lines: 119 In-reply-to: dave@hpgnd.HP.COM's message of 9 Oct 90 13:45:43 GMT In article <1950001@hpgnd.HP.COM> dave@hpgnd.HP.COM (Dave PENKLER) writes: > A recent discussion on whether CL functions are first class objects brought up > a point on the run time creation of functions. This is somthing I missed in CL > and have consequently remained stranded in the ancient world of Ye Old Lisp. > Ye old lisp's abilty to handle functional values can be interpreted as a sort > of support for object oriented development. The beauty of it is its extreme > simplicity in the prinicple of operation permitting at the same time > arbitrarily complex hierachies and collections of objects. For free you have > the ability to modify methods in a given instance, all instances of a class > or future instances. This is great for modelling and simulations where > you may need to tweak individual instances during the run to see what the > effects on the system might be. Dynamic scoping gives you what I call dynamic > inheritance where free variables/methods in the closure are resolved in the > invoking environment and captured in the instance. > Here is an ultra simple example to give the basic idea of functional values > as objects: > To create a class you simply define a function that returns itself in a funarg - > (defun SIMP (X Y) ; inittable instance vars X and Y > (prog (Z SHOW) ; instance var Z and a method SHOW > (setq Z 'some-default) ; initial value of Z > (defun SHOW () (print (list X Y Z))) ; method to print instance vars > (fun SIMP))) ; return self in funarg > To create an instance - > (setq INST1 (SIMP 'fred 'joe)) > To apply the method SHOW to our instance - > (send '(SHOW) INST1) ; show its guts > (fred joe some-default) > The real work here is done by "send" > (defun send (EXP OBJ) (apply (list 'close (car EXP) (caddr OBJ)) (cdr EXP))) > Is there any way to do this sort of thing in newer dialects of lisp ? > DaveP The problem is that the 'close' operator was generally very expensive, having to wind and then unwind the dynamic context (or else do dynamic searching for bindings every time, which is even more expensive.) While not entirely equivalent, this sort of stuff is usually done by being more explicit about the 'search' for the appropriate method, e.g., (defun simp (x y) (let ((z 'some-default)) #'(lambda (method &rest args) (ecase method (show (print (list x y z))) (set-z (setq z (first args))))))) (setq inst1 (simp 'fred 'joe)) ;Usually to avoid interpretation, the "send" primitive separates out the ;method from the arguments, e.g., (defmacro send (method object &rest args) `(funcall ,object ',method ,@args)) ;To use (send show inst1) ; prints (fred joe some-default) (send set-z inst1 'new-z) ; reset z (send show inst1) ; prints (fred joe new-z) ; If you want to evaluate the method, you're better off using a ; function to get order-of-evaluation right: (defun send1 (method object &rest args) (apply object method args)) (send1 'show inst1) (send1 'set-z inst1 'newer-z) (send1 'show inst1) ; If you want to pretty it up and hide the mechanism: (defmacro methods (&rest method-list) `#'(lambda (method &rest args) (ecase method ,@(mapcar #'(lambda (mproc) `(,(car mproc) (apply #'(lambda ,@(cdr mproc)) args))) method-list)))) ; and then you can write (defun simp (x y) (let ((z 'some-default)) (methods (show () (print (list x y z))) (set-z (newz) (setq z newz))))) This is a little bit of a simplification in that you'd want to avoid symbol conflicts either by having 'method' and 'args' in a private package or else using gensyms, e.g.: (defmacro methods (&rest method-list) (let ((mv (gensym)) (av (gensym))) `#'(lambda (,mv &rest ,av) (ecase ,mv ,@(mapcar #'(lambda (mproc) `(,(car mproc) (apply #'(lambda ,@(cdr mproc)) ,av))) method-list)))) -- Larry Masinter (masinter@parc.xerox.com) Xerox Palo Alto Research Center (PARC) 3333 Coyote Hill Road; Palo Alto, CA USA 94304 Fax: (415) 494-4333