From: Shiv
Subject: call-next-next-method
Date: 
Message-ID: <lczozwvkqb.fsf@balrog.ece.ucsb.edu>
I would like to be able to call the next next-method in CLOS.  That
is the method that would be called if the method invoked by
call-next-method called call-next-method.  Is there any direct way to
do it?  Thanks,

--shiv--

Read on for the actual problem ...

I have made-up an artificial problem that hopefully reflects the
essentials of my actual problem.

(defclass matrix ()
  (...))

(defclass lower-triangular-matrix (matrix)
  (...))

(defclass upper-triangular-matrix (matrix)
  (...))

(defclass square-matrix (lower-triangular-matrix upper-triangular-matrix)
  ())

(defgeneric mref (matrix i j)
 (:documentation "Access (i,j)th element of matrix."))

(defmethod mref ((A lower-triangular-matrix) (i integer) (j integer))
  ... )

(defmethod mref ((A upper-triangular-matrix) (i integer) (j integer))
  ... )

It would be nice if I could say:

(defmethod mref ((A square-matrix) (i integer) (j integer))
  (+ (call-next-method) (call-next-next-method)))

or something equivalent to that, like

(defmethod mref ((A square-matrix) (i integer) (j integer))
(+ (call-method
     (find-method #'mref
                  (mapcar #'find-class '(lower-triangular-matrix integer
                                         integer)))
     A i j)
   (call-method
     (find-method #'mref
                  (mapcar #'find-class '(upper-triangular-matrix integer
                  integer)))
     A i j)))

Of course I cannot use call-method in defmethod.  So this doesn't work.

Another option seems to be to extend the standard-method-combination
with a + qualifier (using define-method-combination (long form)) that
would add all the results returned by applicable primary methods,

(defmethod mref + ((A square-matrix) (i integer) (j integer))
 0.0).

Yet another option is to just cut and paste the code together...

From: Barry Margolin
Subject: Re: call-next-next-method
Date: 
Message-ID: <ylGs3.74$m84.1007@burlma1-snr2>
In article <··············@balrog.ece.ucsb.edu>,
Shiv  <····@balrog.ece.ucsb.edu> wrote:
>
>I would like to be able to call the next next-method in CLOS.  That
>is the method that would be called if the method invoked by
>call-next-method called call-next-method.  Is there any direct way to
>do it?  Thanks,

No, you're not supposed to have this much direct control.  You can decide
whether or not to call the next method, by putting a conditional around
call-next-method, but it would be poor modularity to allow you to pick and
choose methods to call.  How do you know that some other class isn't going
to get inserted into the hierarchy, so that the next-next method isn't the
one you really intended to get?

>Another option seems to be to extend the standard-method-combination
>with a + qualifier (using define-method-combination (long form)) that
>would add all the results returned by applicable primary methods,

I believe there's a built-in + method combination.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Marco Antoniotti
Subject: Re: call-next-next-method
Date: 
Message-ID: <lw1zd225m1.fsf@copernico.parades.rm.cnr.it>
Barry Margolin <······@bbnplanet.com> writes:

> In article <··············@balrog.ece.ucsb.edu>,
> Shiv  <····@balrog.ece.ucsb.edu> wrote:
> >
> >I would like to be able to call the next next-method in CLOS.  That
> >is the method that would be called if the method invoked by
> >call-next-method called call-next-method.  Is there any direct way to
> >do it?  Thanks,
> 
> No, you're not supposed to have this much direct control.  You can decide
> whether or not to call the next method, by putting a conditional around
> call-next-method, but it would be poor modularity to allow you to pick and
> choose methods to call.  How do you know that some other class isn't going
> to get inserted into the hierarchy, so that the next-next method isn't the
> one you really intended to get?
> 

The smell of C++ is felt all over the globe.  Since C++ does not help
you in any way when you have multiple inheritance, you must resort to
this sort of things in order to sort out what is being used.

This usually happens after a few recompile cycles.

Cheers

-- 
Marco Antoniotti ===========================================
PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY
tel. +39 - 06 68 10 03 17, fax. +39 - 06 68 80 79 26
http://www.parades.rm.cnr.it/~marcoxa
From: Patrick A. O'Donnell
Subject: Re: call-next-next-method
Date: 
Message-ID: <vytemh74x7w.fsf@ai.mit.edu>
Shiv <····@balrog.ece.ucsb.edu> writes:
> I would like to be able to call the next next-method in CLOS.  ...
> 
> I have made-up an artificial problem that hopefully reflects the
> essentials of my actual problem.
> 
> (defclass matrix () (...))
> (defclass lower-triangular-matrix (matrix) (...))
> (defclass upper-triangular-matrix (matrix) (...))
> (defclass square-matrix (lower-triangular-matrix upper-triangular-matrix)
>   ())


Aside from the question you actually asked, which Barry adequately
answered, I must comment on the type relationships that your example
code defines.  Often when I have method combination problems or
questions, they really arise from a hastily composed class hierarchy
or one that was ill-driven by implementation considerations rather
than by model considerations.

The above class definitions tell me that a square matrix is a subtype
of both a lower triangular matrix and an upper triangular matrix.
Aren't the type relationships really the other way around?

		- Pat
		  ···@alum.mit.edu
From: Shiv
Subject: Re: call-next-next-method
Date: 
Message-ID: <lcwvuzvet0.fsf@balrog.ece.ucsb.edu>
···@ai.mit.edu (Patrick A. O'Donnell) writes:

> Shiv <····@balrog.ece.ucsb.edu> writes:
> > I would like to be able to call the next next-method in CLOS.  ...
> > 
> > I have made-up an artificial problem that hopefully reflects the
> > essentials of my actual problem.
> > 
> > (defclass matrix () (...))
> > (defclass lower-triangular-matrix (matrix) (...))
> > (defclass upper-triangular-matrix (matrix) (...))
> > (defclass square-matrix (lower-triangular-matrix upper-triangular-matrix)
> >   ())
> 
> 
> Aside from the question you actually asked, which Barry adequately
> answered, I must comment on the type relationships that your example
> code defines.  Often when I have method combination problems or
> questions, they really arise from a hastily composed class hierarchy
> or one that was ill-driven by implementation considerations rather
> than by model considerations.
> 
> The above class definitions tell me that a square matrix is a subtype
> of both a lower triangular matrix and an upper triangular matrix.
> Aren't the type relationships really the other way around?
> 
> 		- Pat
> 		  ···@alum.mit.edu

On the face it, sure, the answer is yes.  However, in my code,
"square-matrix" is really a "union" of "lower-triangular-matrix" and
"upper-triangular-matrix".  That is why I was wishing that I could
directly call all the methods at the previous level.

I guess the real answer is that the standard-method-combination is not
appropriate in such a case.

--shiv--
From: Kent M Pitman
Subject: Re: call-next-next-method
Date: 
Message-ID: <sfwiu6j4mta.fsf@world.std.com>
Shiv <····@balrog.ece.ucsb.edu> writes:

> On the face it, sure, the answer is yes.  However, in my code,
> "square-matrix" is really a "union" of "lower-triangular-matrix" and
> "upper-triangular-matrix".  That is why I was wishing that I could
> directly call all the methods at the previous level.

This usually means you're short one protocol.  Just name the methods 
that you want to call something that can be accessed by name.  That 
is, if you want to call FOO one level up, make the one-level-up method
be called FOO-AUX and then make the FOO method on that class call FOO-AUX
but also make your inheriting methods call FOO-AUX if they want to.
 
> I guess the real answer is that the standard-method-combination is not
> appropriate in such a case.

I'm not sure method combination at all is your friend here.
This sounds to me like a case where you want to dead-reckon a particular
item (which is what "naming" is for).  Method combination is for
relative/vague naming ("call that thing above me" or "call those 
other things"); it is specifically not about absolute naming.
From: Shiv
Subject: Re: call-next-next-method
Date: 
Message-ID: <lcr9l7v7ru.fsf@balrog.ece.ucsb.edu>
Kent M Pitman <······@world.std.com> writes:

> Shiv <····@balrog.ece.ucsb.edu> writes:
> 
> > On the face it, sure, the answer is yes.  However, in my code,
> > "square-matrix" is really a "union" of "lower-triangular-matrix" and
> > "upper-triangular-matrix".  That is why I was wishing that I could
> > directly call all the methods at the previous level.
> 
> This usually means you're short one protocol.  Just name the methods 
> that you want to call something that can be accessed by name.  That 
> is, if you want to call FOO one level up, make the one-level-up method
> be called FOO-AUX and then make the FOO method on that class call FOO-AUX
> but also make your inheriting methods call FOO-AUX if they want to.

Thanks.  That is what I ended up doing.

--shiv--
From: Howard R. Stearns
Subject: Re: call-next-next-method
Date: 
Message-ID: <37B4798E.2AF46804@citydesktopinc.com>
To expand on this and what Pat O'Donnell said:

I like to distinguish between things which ARE a number of other things
(kind-of or mixin inheritance) and thigns which HAVE a number of other
things (part-of or part-whole inheritance).  CLOS directly supports only
the first, so we get very used to thinking in kind-of terms.  

If a model suggest, for example, that a matrix has two parts, then we're
dealing with part-whole arrangements.  CLOS doesn't address any
automatic combinations of these, so whenever this comes up you will
ALWAYS need an named "auxiliary" function.  

It's sometimes easy and/or desirable to combine the two styles, as when
the two parts do not interfere with each other at all.  Then we might
have a supply-part-A-mixin, and a supply-part-B-mixin.  That doesn't
change the fact that we're still dealing with part-whole, and still
require a mechanism other than the CLOS provided inheritance and method
combination. 


Kent M Pitman wrote:
> 
> Shiv <····@balrog.ece.ucsb.edu> writes:
> 
> > On the face it, sure, the answer is yes.  However, in my code,
> > "square-matrix" is really a "union" of "lower-triangular-matrix" and
> > "upper-triangular-matrix".  That is why I was wishing that I could
> > directly call all the methods at the previous level.
> 
> This usually means you're short one protocol.  Just name the methods
> that you want to call something that can be accessed by name.  That
> is, if you want to call FOO one level up, make the one-level-up method
> be called FOO-AUX and then make the FOO method on that class call FOO-AUX
> but also make your inheriting methods call FOO-AUX if they want to.
> 
> > I guess the real answer is that the standard-method-combination is not
> > appropriate in such a case.
> 
> I'm not sure method combination at all is your friend here.
> This sounds to me like a case where you want to dead-reckon a particular
> item (which is what "naming" is for).  Method combination is for
> relative/vague naming ("call that thing above me" or "call those
> other things"); it is specifically not about absolute naming.
From: Patrick A. O'Donnell
Subject: Re: call-next-next-method
Date: 
Message-ID: <vytd7wr4bpj.fsf@ai.mit.edu>
Shiv <····@balrog.ece.ucsb.edu> writes:
> ···@ai.mit.edu (Patrick A. O'Donnell) writes:
> > Shiv <····@balrog.ece.ucsb.edu> writes:
> > > (defclass matrix () (...))
> > > (defclass lower-triangular-matrix (matrix) (...))
> > > (defclass upper-triangular-matrix (matrix) (...))
> > > (defclass square-matrix (lower-triangular-matrix upper-triangular-matrix)
> >
> > The above class definitions tell me that a square matrix is a subtype
> > of both a lower triangular matrix and an upper triangular matrix.
> > Aren't the type relationships really the other way around?
> 
> On the face it, sure, the answer is yes.  However, in my code,
> "square-matrix" is really a "union" of "lower-triangular-matrix" and
> "upper-triangular-matrix".  That is why I was wishing that I could
> directly call all the methods at the previous level.

My point, though, is that (typep x 'lower-triangular-matrix) will
return true for a general square matrix.  Is that what you really
want?  My message was intended to concentrate on the type
relationships irrespective of the method combination issues.

On the topic of method combinations, however, I will offer the
observation that I have often regretted attempts to use method
combination types other than standard.  Similar to Kent's message,
most of the time I've though I've needed something other than primary,
before, after, and around, I've later found that I really had a badly
designed, half-baked protocol.  Sadly, it's almost always to late to
fix it by the time one realizes that.

		- Pat
		  ···@alum.mit.edu
From: Erik Naggum
Subject: Re: call-next-next-method
Date: 
Message-ID: <3143985782199982@naggum.no>
* Shiv <····@balrog.ece.ucsb.edu>
| I have made-up an artificial problem that hopefully reflects the
| essentials of my actual problem.
| 
| (defclass matrix ()
|   (...))
| 
| (defclass lower-triangular-matrix (matrix)
|   (...))
| 
| (defclass upper-triangular-matrix (matrix)
|   (...))
| 
| (defclass square-matrix (lower-triangular-matrix upper-triangular-matrix)
|   ())

  why not simply talk about the parts

(defclass square-matrix (matrix)
  ((lower-triangle :type lower-triangular-matrix)
   (upper-triangle :type upper-triangular-matrix)))

| It would be nice if I could say:
| 
| (defmethod mref ((A square-matrix) (i integer) (j integer))
|   (+ (call-next-method) (call-next-next-method)))

  why is the following the wrong solution?

(defmethod mref ((A square-matrix) (i integer) (j integer))
  (+ (mref (slot-value A 'lower-triangle) i j)
     (mref (slot-value A 'upper-triangle) i j)))

#:Erik
-- 
  (defun pringles (chips)
    (loop (pop chips)))
From: Shiv
Subject: Re: call-next-next-method
Date: 
Message-ID: <lck8qsdfjg.fsf@balrog.ece.ucsb.edu>
Erik Naggum <····@naggum.no> writes:

>   why not simply talk about the parts
> 
> (defclass square-matrix (matrix)
>   ((lower-triangle :type lower-triangular-matrix)
>    (upper-triangle :type upper-triangular-matrix)))
> 
> | It would be nice if I could say:
> | 
> | (defmethod mref ((A square-matrix) (i integer) (j integer))
> |   (+ (call-next-method) (call-next-next-method)))
> 
>   why is the following the wrong solution?
> 
> (defmethod mref ((A square-matrix) (i integer) (j integer))
>   (+ (mref (slot-value A 'lower-triangle) i j)
>      (mref (slot-value A 'upper-triangle) i j)))
> 
> #:Erik
> -- 
>   (defun pringles (chips)
>     (loop (pop chips)))

This was the first approach I tried.  Unfortunately, it looked like it
would cause a lot of code duplication (other than just mref) and I
went with the subclass approach instead.

--shiv--
From: Erik Naggum
Subject: Re: call-next-next-method
Date: 
Message-ID: <3144000912483445@naggum.no>
* Shiv <····@balrog.ece.ucsb.edu>
| Unfortunately, it looked like it would cause a lot of code duplication
| (other than just mref) and I went with the subclass approach instead.

  um, do I get this?  the approach would work, but would involve some code
  duplication, so you abandoned it for one that involves a lot less code
  that _doesn't_ work?

  code duplication is generally solved with macros.  in general, most of
  the CLOS magic is indeed macros and machinery that has been created for
  you, otherwise it would have caused a lot of difficult code duplication,
  so I don't see why "code duplication" doesn't _precisely_ mean that you
  automate the task of duplication yourself.

#:Erik
-- 
  (defun pringles (chips)
    (loop (pop chips)))
From: Pierre R. Mai
Subject: Re: call-next-next-method
Date: 
Message-ID: <87wvushrri.fsf@orion.dent.isdn.cs.tu-berlin.de>
Shiv <····@balrog.ece.ucsb.edu> writes:

[ Proposed use of composition instead of inheritance elided ]

> This was the first approach I tried.  Unfortunately, it looked like it
> would cause a lot of code duplication (other than just mref) and I
> went with the subclass approach instead.

Would not a combined approach of composition and inheritance solve
some of your code duplication?  I.e. is the duplicated code really
specific to upper- and lower-triangular-matrix, or can it be lifted up 
to some higher level (like one abstract super class, or many mixin
classes)?  In this case you could let square-matrix inherit from
applicable mixins (or super classes), _and_ contain instances of
upper- and lower-triangular-matrix.  The only code you would need to
supply would be code that indicated the delegation of operations to
the components (which by definition can't be duplicated code), and
code that is specific to square-matrix itself.

And should there be code duplication elsewhere, I'd want to see a more
complete example of the thing you want to do, to see where it comes
from.  In cases where other mechanisms of avoiding code duplication
fail, you can indeed use macrology to reduce this code duplication, as
Erik suggested.  But it seems to me that you should first identify the 
inner relationships of your model, to understand the root causes of
your code duplication...

Regs, Pierre.

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Rob Warnock
Subject: Re: call-next-next-method
Date: 
Message-ID: <7plvq0$2usl7@fido.engr.sgi.com>
Erik Naggum  <····@naggum.no> wrote:
+---------------
|   why is the following the wrong solution?
| 
| (defmethod mref ((A square-matrix) (i integer) (j integer))
|   (+ (mref (slot-value A 'lower-triangle) i j)
|      (mref (slot-value A 'upper-triangle) i j)))
+---------------

Hmmm... There's something basically wrong with the whole approach of
the original problem statement that I just noticed in Erik's formulation
of this "mref", namely: In normal matrix algebra, both the lower- and
upper-triangle representations usually *include* the main diagonal, so
if a square-matrix is just a struct of a lower and an upper, a bunch of
constructor-time & mutator-time constraint/consistency stuff is going to
be needed to guarantee that the two diagonals stay consistent!


-Rob

-----
Rob Warnock, 8L-846		····@sgi.com
Applied Networking		http://reality.sgi.com/rpw3/
Silicon Graphics, Inc.		Phone: 650-933-1673
1600 Amphitheatre Pkwy.		FAX: 650-933-0511
Mountain View, CA  94043	PP-ASEL-IA