From: Johann Hibschman
Subject: clos: operate-as?
Date: 
Message-ID: <mt90iacsnq.fsf@astron.berkeley.edu>
Hi,

I have a class "class3" which derives from two other classes, "class1"
and "class2".  Both of those classes implement a method, "foo."

I want to define foo for class3 as:

  (defmethod foo ((inst class3))
    (+ (foo (operate-as 'class1 inst))
       (foo (operate-as 'class2 inst)))

where "operate-as" tells inst to pretend to be an instance of one of
its superclasses.  How can I get this result?

Conceptually, this should be doable, since class3 contains all of the
required slots to be both a class1 and a class2.

change-class seems close to the right idea, but I don't want to
actually change the instance in question, since that would lose
information.  call-next-method could be used to get to one of the
methods in question, but I'd need a "call-next-next-method" to get to
the other.

-- 
Johann Hibschman                           ······@physics.berkeley.edu

From: Barry Margolin
Subject: Re: clos: operate-as?
Date: 
Message-ID: <2SgX1.83$Sg6.657889@burlma1-snr1.gtei.net>
In article <··············@astron.berkeley.edu>,
Johann Hibschman  <······@physics.berkeley.edu> wrote:
>I have a class "class3" which derives from two other classes, "class1"
>and "class2".  Both of those classes implement a method, "foo."
>
>I want to define foo for class3 as:
>
>  (defmethod foo ((inst class3))
>    (+ (foo (operate-as 'class1 inst))
>       (foo (operate-as 'class2 inst)))
>
>where "operate-as" tells inst to pretend to be an instance of one of
>its superclasses.  How can I get this result?

It looks to me like you're just trying to duplicate the functionality of
method combinations.  If you define the FOO generic function to use
:method-combination + then it will automatically sum the results of the +
method of all the superclasses.

Another way to do it is to define methods (or ordinary functions)
CLASS1-FOO and CLASS2-FOO.  You would then write:

(defmethod foo ((inst class1))
  (class1-foo inst))
(defmethod foo ((inst class2))
  (class2-foo inst))

(defmethod foo ((inst class3))
  (+ (class1-foo inst) (class2-foo inst)))

This doesn't seem to be ass object-oriented, though.  But what you're
trying to do isn't really object-oriented, since your use of OPERATE-AS is
essentially overriding the normal generic function lookup, in favor of a
static class specification.  If you're going to do that, you might as well
use class-specific functions.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
From: Johann Hibschman
Subject: Re: clos: operate-as?
Date: 
Message-ID: <mtzpapx0ra.fsf@astron.berkeley.edu>
Barry Margolin <······@bbnplanet.com> writes:

> In article <··············@astron.berkeley.edu>,
> Johann Hibschman  <······@physics.berkeley.edu> wrote:
> 
> It looks to me like you're just trying to duplicate the functionality of
> method combinations.  If you define the FOO generic function to use
> :method-combination + then it will automatically sum the results of the +
> method of all the superclasses.

:method-combination looks interesting; I just read up on it.  I don't
think it quite does what I want it to, though.  Here's a more detailed
class hierarchy: 

                source
           /------+------\
    compton-source  curvature-source
           \------|------/
             both-source

I have a generic function

        (defgeneric call (source energy))

which takes a source and returns the output of that source at a given
energy.  "both-source" is the aggregate of the compton-source and
curvature-source.  I'm looking for a way to express this.

I don't think :method-combination + would work for this, since source
itself doesn't have a useful call method, and I want to have the
option of further subclassing curvature-source, as, say,
general-relativistic-curvature-source without adding in the result
from curvature-source.

> Another way to do it is to define methods (or ordinary functions)
> CLASS1-FOO and CLASS2-FOO.  You would then write:
> 
> (defmethod foo ((inst class1))
>   (class1-foo inst))
> (defmethod foo ((inst class2))
>   (class2-foo inst))
> 
> (defmethod foo ((inst class3))
>   (+ (class1-foo inst) (class2-foo inst)))
> 
> This doesn't seem to be ass object-oriented, though.  But what you're
> trying to do isn't really object-oriented, since your use of OPERATE-AS is
> essentially overriding the normal generic function lookup, in favor of a
> static class specification.  If you're going to do that, you might as well
> use class-specific functions.

This looks like what I'll have to do.  As I'm a CLOS novice, I thought
there might be a better way.

Thanks for your advice.

-- 
Johann Hibschman                           ······@physics.berkeley.edu
From: Howard R. Stearns
Subject: Re: clos: operate-as?
Date: 
Message-ID: <362E24C8.B636F3B3@elwood.com>
Forget CLOS and programming for a moment.  How would you describe the
physics?

For example, suppose you said, "The energy is the sum of all the
different kinds of energies represented by the source".  Then you would
look for a way to program this, and CLOS provides a nice fit in the +
pre-defined method combination.  (By the way, it doesn't matter that
some mixin doesn't defined a method.  Method combination creates an
effective method from all the APPLICABLE methods.  If some potential
method is not applicable (perhaps becuase it was never defined at all),
then it just doesn't enter into it.)

On the other hand, suppose you said: "The energy is different for each
source.  There different kinds of energies.  Some sources use one of
these energies, while others use combinations of these."  In this case,
as Barry points out, the problem isn't really very object-oriented, and
you would use differently named methods and sum them explicitly when
necessarry.


Johann Hibschman wrote:
> 
> Barry Margolin <······@bbnplanet.com> writes:
> 
> > In article <··············@astron.berkeley.edu>,
> > Johann Hibschman  <······@physics.berkeley.edu> wrote:
> >
> > It looks to me like you're just trying to duplicate the functionality of
> > method combinations.  If you define the FOO generic function to use
> > :method-combination + then it will automatically sum the results of the +
> > method of all the superclasses.
> 
> :method-combination looks interesting; I just read up on it.  I don't
> think it quite does what I want it to, though.  Here's a more detailed
> class hierarchy:
> 
>                 source
>            /------+------\
>     compton-source  curvature-source
>            \------|------/
>              both-source
> 
> I have a generic function
> 
>         (defgeneric call (source energy))
> 
> which takes a source and returns the output of that source at a given
> energy.  "both-source" is the aggregate of the compton-source and
> curvature-source.  I'm looking for a way to express this.
> 
> I don't think :method-combination + would work for this, since source
> itself doesn't have a useful call method, and I want to have the
> option of further subclassing curvature-source, as, say,
> general-relativistic-curvature-source without adding in the result
> from curvature-source.
> 
> > Another way to do it is to define methods (or ordinary functions)
> > CLASS1-FOO and CLASS2-FOO.  You would then write:
> >
> > (defmethod foo ((inst class1))
> >   (class1-foo inst))
> > (defmethod foo ((inst class2))
> >   (class2-foo inst))
> >
> > (defmethod foo ((inst class3))
> >   (+ (class1-foo inst) (class2-foo inst)))
> >
> > This doesn't seem to be ass object-oriented, though.  But what you're
> > trying to do isn't really object-oriented, since your use of OPERATE-AS is
> > essentially overriding the normal generic function lookup, in favor of a
> > static class specification.  If you're going to do that, you might as well
> > use class-specific functions.
> 
> This looks like what I'll have to do.  As I'm a CLOS novice, I thought
> there might be a better way.
> 
> Thanks for your advice.
> 
> --
> Johann Hibschman                           ······@physics.berkeley.edu
From: Barry Margolin
Subject: Re: clos: operate-as?
Date: 
Message-ID: <nsrX1.133$Sg6.948321@burlma1-snr1.gtei.net>
In article <·················@elwood.com>,
Howard R. Stearns <······@elwood.com> wrote:
>On the other hand, suppose you said: "The energy is different for each
>source.  There different kinds of energies.  Some sources use one of
>these energies, while others use combinations of these."  In this case,
>as Barry points out, the problem isn't really very object-oriented, and
>you would use differently named methods and sum them explicitly when
>necessarry.

Right.  I don't really know the problem domain, but maybe it's not even
appropriate to represent this relationship using subclasses.  It might be
more appropriate for a both-source object to have the constituents as a
component (i.e. a slot containing a list of other sources); it could have a
method like:

(defun energy ((self sum-source))
  (reduce #'+ (component-sources self)))

Too often novice OO programmers try to use subclassing for everything.  For
instance, they might do something like:

(defclass automobile (tires body engine ...))

Subclasses usually represent IS-A relationship, but somtimes people try to
use them to represent HAS-A, and it frequently results in contorted code
when you do this.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
From: Johann Hibschman
Subject: Re: clos: operate-as?
Date: 
Message-ID: <mt7lxrxg5c.fsf@astron.berkeley.edu>
Barry Margolin <······@bbnplanet.com> writes:

> Right.  I don't really know the problem domain, but maybe it's not even
> appropriate to represent this relationship using subclasses.  It might be
> more appropriate for a both-source object to have the constituents as a
> component (i.e. a slot containing a list of other sources); it could have a
> method like:
> 
> (defun energy ((self sum-source))
>   (reduce #'+ (component-sources self)))

Hmm.  I must admit that I'm not using terribly pure OO here.  The
"object" is a function, a mapping from energies to number of photons
output at that energy.  I made it a class, since there are several
types of functions like this which all share certain dependences on
position, system parameters, etc.

That worked, until I wanted to express another function object, like
the others, which was the sum of two other objects.  I don't want to
combine full instances of the objects into one, since they share a lot
of information, and I would have to keep this information in synch
somehow.

I.e. assume I have functions which take a whole lot of parameters,
which change very rarely, in addition to their main argument.  Most of
these slowly-changing parameters are the same for multiple functions,
but each function has one or two parameter of its own.

f(x; q,     a,b,c,d...)
g(x; r,s,   a,b,c,d...)
h(x; q,r,s, a,..)       = f(x;...) + g(x;...)

I was using a base class to handle all of the basic parameters (a, b,
...), stash the right precomputed coefficients in the right places,
etc.  I then defined f and g.  Now I want to define h.

So far I still think the idea of just combining the appropriate
methods by hand is the simplest.  If I start making it too tricky,
I'll have no idea what I did by the time I look back at the code in a
month.

-- 
Johann Hibschman                           ······@physics.berkeley.edu