Re: Is there a call-NEXT-next-method, or casting in CLOS?
- From: Mirko.Vukovic@xxxxxxxxx
- Date: Fri, 26 Sep 2008 09:26:46 -0700 (PDT)
On Sep 26, 4:11 am, Rainer Joswig <jos...@xxxxxxx> wrote:
In article
<d80f6ae8-abd7-4e99-b8b6-30d7a0c15...@xxxxxxxxxxxxxxxxxxxxxxxxxxxx>,
Mirko.Vuko...@xxxxxxxxx wrote:
On Aug 12, 4:02 am, Rainer Joswig <jos...@xxxxxxx> wrote:
In article
<429e8636-1b84-4130-965f-b16f70ff1...@xxxxxxxxxxxxxxxxxxxxxxxxxxx>,
Yarek Kowalik <yarek.kowa...@xxxxxxxxx> wrote:
This is a general CLOS question that I have run into a few times this
past week and I don't know how to solve.
I have abaseclass foo that has amethoddo-action.
(methoddo-action ((obj foo))
.... )
Classes don't have methods in CLOS. That model is not applicable for CLOS.
Methods are defined outside of classes as parts of generic functions.
Methods can be specialized for more than one parameter, which makes the
'belongs to a class' idea even more false.
(defmethod do-something ((a foo) (b bar)) ... )
To which class should abovemethodbelong ?
I also have a subclass bar of foo that specializes themethoddo-
action
(methoddo-action ((obj bar))
.... )
Again, bar can't specialize methods, since classes don't
define methods and methods don't belong to classes.
You really need to be object-reoriented (see Peter Seibel's book
for that).
Now, I have a baz subclass of bar for which I don't want bar's do-
action, but instead I wantbaseclass foo's do-action. Therefore, I
cannotcallcall-next-method, since that would invoke bar's do-action..
Is there a way to type cast baz to foo so that I can invoke do-action
for foo from baz? Or is there a techique for makeing acall-next-next-
methodor equivalent?
Your problem looks a bit weird and you might want to redesign the whole thing.
But...
(defclass c1 () ())
(defclass c2 () ())
(defclass c3 () ())
See above, no methods. Classes don't take any methods.
I also haven't defined any inheritance above.
(defmethod m1 ((a c1)) (print 'm1))
FirstMethodm1 takes one argument of class c1.
(defmethod m1 ((a c2)) (print 'm2))
SecondMethodm1 takes one argument of class c2.
(defmethod m1 ((a c3))
(funcall (method-function (find-method#'m1 () (list (find-class 'c1)))) a)
(print 'm3))
Thirdmethodm3 takes one argument of class c3
FIND-METHODfinds amethodbased on a list ofmethod-qualifiers and a list of specializers.
In this case the specializers list is just a list of the class c1.
METHOD-FUNCTION is a MOP function (not in ANSI CL, but defined by many CL implementations)
that gets the function of amethod, funcall calls it with a.
... stuff deleted
I am having trouble extending this example (I am mindful of the
comments other have made about the need to re-arrange the object
hierarchy, and I will say a bit about my problem below).
Anyway, here is my simple hierarchy. (The difference from the above,
is that I am passing arguments to the methods, and that is where
things are braking.)
(in-package :cl-user)
(defclass base ()
((base-prop-1 :initform nil :accessor base-prop-1)))
(defclass super1a (base)
((super1a-prop-1 :initform 2
:accessor super1a-prop-1)))
Note that usually SUPER1A is said to be a subclass of the class BASE.
Not a superclass.
I always get confused. Thanks for the clarification.
CL-USER 262 > (class-direct-subclasses (find-class 'base))
(#<STANDARD-CLASS SUPER1A 41F066845B>)
(defgeneric method1 (class arg &key &allow-other-keys)
(:documentation "Execute operation"))
(defmethod method1 ((this base) (arg integer) &key &allow-other-keys)
arg)
(defmethod method1 ((this super1a) arg &key key1)
(expt arg (or key1 (super1a-prop-1 this))))
;; invocation that does not work:
(let ((b (make-instance 'base))
(s (make-instance 'super1a)))
(print (method1 b 5))
(print (method1 s 5 :key1 3))
(apply (sb-mop:method-function
(find-method #'method1 '()
(list (find-class 'base) 'integer)))
s 5))
You would need to use the class INTEGER, not the symbol:
CL-USER 260 > (find-method #'method1 nil (list (find-class 'base) (find-class 'integer)))
#<STANDARD-METHOD METHOD1 NIL (BASE INTEGER) 41F066815B>
This finds the other method:
CL-USER 261 > (find-method #'method1 nil (list (find-class 'super1a) (find-class 't)))
#<STANDARD-METHOD METHOD1 NIL (SUPER1A T) 41F066C293>
CL-USER 276 > (let ((b (make-instance 'base))
(s (make-instance 'super1a)))
(print (method1 b 5))
(print (method1 s 5 :key1 3))
(funcall (method-function (find-method #'method1 '() (list (find-class 'base) (find-class 'integer))))
s 5 nil))
5
125
5
I guess how to call the METHOD-FUNCTION is implementation dependent (I haven't
checked that).
Aaah, thanks.
You can see that I specialized method1 on base & integer (following
the example from hyperspec), because that was the only way that I
could make find-method find the method. I would prefer to leave the
integer specification blank for now, but then I did not know how to
specify the last argument of find-method. It needed a two element
list, and I did not know how to specify the un-typed second argument.
My second problem is that apply fails. I am passing it the superobject
and the numeric argument, but it is asking for a type of list.
So much about the example itself. Now a few words about why I need
this method overriding. I am writing a simple 1D partial differential
equation solver. For the un-initiated, this reduces to a linear
algebra problem (and here is a plug for the excellent gsll lisp
library) which consists of specifying how to fill out a matrix M and
its right hand side vector B:
M X = B
Our solution is X.
When solving differential equations, one also needs to specify
boundary conditions (like what is the temperature at the boundaries,
or how much heat is flowing in and out). This amounts to specifying
the contents of the first and last rows of the matrix and the right
hand side vector.
My problem has to deal with the boundary conditions and the hierarchy
of solvers. My solver hierarchy progresses from a base class that
sets up storage, and several supperclasses that add additional
properties based on the physics (ok, and chemistry) that I am solving,
such as diffusion, diffusion + drift, time dependence.
Each of these superclasses has their way of specifying the boundary
conditions in terms of the matrix problem. The base class also has a
way of specifying the boundary conditions in the most "naive" way,
naive in the sense that it does not take into account the physics of
the problem (remember, the physics is in the superclasses).
So, I have a generic method calc-bc-coeffs. The base class and the
superclasses each have their own method that is specialized to their
case.
However, there are cases (and these are really exceptions that I use
for testing purposes mainly), where I would like the superclasses to
use the base class' calc-bc-coeffs instead of its own. In pseudo-
code:
(let ((solver (make-instance '1d-diff-solver))
(load-bulk-mat solver)
(load-left-bc (base-class solver) left-bc)
(load-right-bc (base-class solver) right-bc))
It is for those cases that I am interested in this thread.
Thanks
Mirko
Probably you might want to start thinking learning about
METHOD-COMBINATIONs. You think you need a special way
of method ordering and calling.
CLOS
a) allows multiple arguments to be used for dispatching -> methods don't belong to classes
b) CLOS sorts the applicable methods (to the provided arguments) in some order
c) with normal method combination you can specify primary, :around, :before and :after methods
d) :around methods and primary methods can use CALL-NEXT-METHOD to call the next method
Method combinations allow you to provide other machineries that the above..
But a simpler version would be (a sketch):
(defclass base-class () ())
(defclass subclass-1 (base-class) ())
(defmethod foo-base ((base base-class) bar)
...)
(defmethod foo ((base base-class) bar)
(foo-base base bar))
(defmethod foo ((sub-1 subclass-1) bar)
.....
)
(let ((i (make-instance 'subclass-1)))
(foo i 15)
(foo-base i 15))
--http://lispm.dyndns.org/
Actually, I was thinking just to create a new generic method and its
implementation attached to the base class, that does the thing, and is
not over-ridden by subclasses.
Thanks again,
Mirko
.
- References:
- Re: Is there a call-NEXT-next-method, or casting in CLOS?
- From: Mirko . Vukovic
- Re: Is there a call-NEXT-next-method, or casting in CLOS?
- From: Rainer Joswig
- Re: Is there a call-NEXT-next-method, or casting in CLOS?
- Prev by Date: Re: Is there a call-NEXT-next-method, or casting in CLOS?
- Next by Date: Re: Lisp Design Patterns
- Previous by thread: Re: Is there a call-NEXT-next-method, or casting in CLOS?
- Next by thread: Re: Is there a call-NEXT-next-method, or casting in CLOS?
- Index(es):
Relevant Pages
|