Re: CLOS question



Rainer Joswig <joswig@xxxxxxxxxxxxxx> writes:

In article <f8j0o8$8qc$1@xxxxxxxxxxxxxxxxxxxxxxxxxxxxx>,
stamant@xxxxxxxx (Rob St. Amant) wrote:

I have what seems like a familiar CLOS question, but a quick Google
search doesn't turn up an answer: I have a method, m, and an after
method for it. The after method is specialized on class c. I'd like
to define a class d that inherits c, and have instances of d behave
just like instances of c *except* for that single after method.

I don't believe that I can prevent the after method for class c from
being run when m is called on an instance of d.

Right. All :after methods will be executed.

(Though it would be
convenient if I were wrong about this.) My question is about the
choices for design. I could break class c into two classes, c1 and
c2, and only define the after method for c2, and have d inherit c1,
but I'm wondering if there are other reasonable designs.

Then you get to a more Mixin-style of programming.

Other options:

* use another method combination, maybe write your own one

It might look like this:

#| frame method combination runs the most specific :open method if any, the
most specific primary method, and the most specific :close method if any,
finally return the result of the primary method. Less specific primary methods
are runnable via call next method.

The key words are :open and :close leaving :before and :after available for
use in a more elaborate version. |#

(define-method-combination frame ()
((open (:open))
(primary () :required t)
(close (:close)))
`(progn
(print (list ,(length open) ;remove once debugged
,(length primary)
,(length close)))
,(if open
`(call-method ,(first open))
nil)
(prog1
(call-method ,(first primary)
,(rest primary))
,(if close
`(call-method ,(first close))
nil))))

(defclass c ()())
(defclass d (c)())

(defgeneric act (object)
(:method-combination frame)
(:method ((o c))
(format t "~&Primary method for class C actually working on ~A."
(class-of o))
'C)
(:method :close ((o c))
(format t "~&Close class C, called on class ~A."
(class-of o)))
(:method ((o d))
(format t "~&Primary method for class D called on ~A."
(class-of o))
(if (y-or-n-p "Call next method? ")
(call-next-method)
'that-all-folks)))

With these definitions the close method acts as an after
method,

CL-USER> (act (make-instance 'c))

(0 1 1)
Primary method for class C actually working on #<STANDARD-CLASS C {48B7EBC5}>.
Close class C, called on class #<STANDARD-CLASS C {48B7EBC5}>.

C

we still get the return value from the primary method

The frame combination allows you to call next method

CL-USER> (act (make-instance 'd))

(0 2 1)
Primary method for class D called on #<STANDARD-CLASS D {48BA6EB5}>.
Call next method? y

Primary method for class C actually working on #<STANDARD-CLASS D {48BA6EB5}>.
Close class C, called on class #<STANDARD-CLASS D {48BA6EB5}>.

C

Or not

CL-USER> (act (make-instance 'd))

(0 2 1)
Primary method for class D called on #<STANDARD-CLASS D {48BA6EB5}>.
Call next method? n

Close class C, called on class #<STANDARD-CLASS D {48BA6EB5}>.

THAT-ALL-FOLKS

The point of it is to be able to turn off less specific
close methods

(defmethod act :close ((o d)) nil) ;no closing action for class D

CL-USER> (act (make-instance 'd))

(0 2 2)
Primary method for class D called on #<STANDARD-CLASS D {48BA6EB5}>.
Call next method? n

THAT-ALL-FOLKS

The close method has been turned off for D, but its still
there for C:

CL-USER> (act (make-instance 'c))

(0 1 1)
Primary method for class C actually working on #<STANDARD-CLASS C {48B7EBC5}>.
Close class C, called on class #<STANDARD-CLASS C {48B7EBC5}>.

C


Alan Crowe
Edinburgh
Scotland
.