[comp.lang.clos] method definition question

alanr@chopin.media-lab.media.mit.edu (Alan Ruttenberg) (06/18/91)

I have a question concerning creating a method applicable to one of
two classes.

Suppose I have two classes A and B. These two classes are distinct.
They happen to share similar instance variables, but it is not
possible to factor this out to a mixin, since I can't redefine A.

I want to write a method which is applicable to either. The cleanest way to
express it is:

(deftype C () '(or A B))

(defmethod common ((instance C))
 ...)

This doesn't work. (can't find class C)

My only two choices seem to be to either replicate the code, or to factor the
body of the definition of common into a defun which is called by both.

1-

(defmethod common ((instance A))
  the code)
(defmethod common ((instance B))
  the same code)

2-

(defmethod common ((instance A))
  (the-code instance))
(defmethod common ((instance B))
  (the-code instance))
(defun the-code (instance)
  the code)

So the question is... Is there a more elegant way to do this?

-alan

barmar@think.com (Barry Margolin) (06/18/91)

In article <ALANR.91Jun17130803@chopin.media-lab.media.mit.edu> alanr@chopin.media-lab.media.mit.edu (Alan Ruttenberg) writes:
>(deftype C () '(or A B))
>
>(defmethod common ((instance C))
> ...)
>
>This doesn't work. (can't find class C)
>
>My only two choices seem to be to either replicate the code, or to factor the
>body of the definition of common into a defun which is called by both.

If A and B have any ancestors in common you could define the method on a
common ancestor, and then use (check-type instance 'C) to catch misuse.
But that's also pretty inelegant.  

I don't think there's a really elegant way to do this.  OO programming
generally depends on OO design, and it can get clumsy when you don't have
the luxury of redesigning pieces.  There was another posting today about
adding a mixin to an existing class for which the source isn't available;
that's the same kind of problem.

Compound type specifiers such as OR can't be used as method specializers
because they can introduce ambiguities into the class hierarchy.  For
instance, if you had

(deftype OR1 () '(or A B))
(defmethod common ((instance OR1)) ...)

(deftype OR2 () '(or B C))
(defmethod common ((instance OR2)) ...)

and then did (common (make-instance 'B)), which method should be chosen?

Of your two choices, I'd say the second one (factoring the common code into
an ordinary function) is better.  This is the nice thing about the fact
that CLOS doesn't restrict slot access only to methods.
-- 
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

jonl%kuwait@lucid.com (Jon L White) (06/18/91)

Date: Mon, 17 Jun 91 17:45:54 -0400
From: Mail Delivery Subsystem <Mailer-Daemon@cis.ohio-state.edu>
Subject: Returned mail: Service unavailable
To: <jonl%kuwait@lucid.com>

   ----- Transcript of session follows -----
>>> DATA
<<< 554 sendall: too many hops (17 max)
554 <comp.lang.clos@cis.ohio-state.edu>... Service unavailable: Bad file number

   ----- Unsent message follows -----

. . . 

Date: Mon, 17 Jun 91 14:06:25 PDT
From: Jon L White <jonl%kuwait@lucid.com>
Message-Id: <9106172106.AA06676@kuwait>
To: alanr@chopin.media-lab.media.mit.edu
Cc: comp.lang.clos@cis.ohio-state.edu
In-Reply-To: Alan Ruttenberg's message of 17 Jun 91 18:08:03 GMT <ALANR.91Jun17130803@chopin.media-lab.media.mit.edu>
Subject: method definition question

re: My only two choices seem to be to either replicate the code, or to factor 
    the body of the definition of common into a defun which is called by both.

Procedure abstraction is an excellent technique! (the "common defun"
approach -- Object-oriented programming notwithstanding, reports of
the death of the procedural style are premature.)

By the bye, you'd better take another look at the CLOS spec regarding
the integration of types and classes.  DEFTYPE neither creates any
new types (it is like a macro for type names) nor does it even make
any classes.


-- JonL --

lgm@cbnewsc.ATT.COM (lawrence.g.mayka) (06/19/91)

In article <1991Jun17.210108.29347@Think.COM> barmar@think.com (Barry Margolin) writes:
   In article <ALANR.91Jun17130803@chopin.media-lab.media.mit.edu> alanr@chopin.media-lab.media.mit.edu (Alan Ruttenberg) writes:
   >(deftype C () '(or A B))
   >
   >(defmethod common ((instance C))
   > ...)
   >
   >This doesn't work. (can't find class C)
   >
   >My only two choices seem to be to either replicate the code, or to factor the
   >body of the definition of common into a defun which is called by both.

   If A and B have any ancestors in common you could define the method on a
   common ancestor, and then use (check-type instance 'C) to catch misuse.
   But that's also pretty inelegant.  

If A and B are standard classes, they are guaranteed to have
STANDARD-OBJECT as a common superclass; the method can be specialized
on that.  And any vendor that allows for run-time modification of the
class hierarchy should be able to optimize slot accesses in such a
method just as well as in more specialized methods.  In an ordinary
function, on the other hand, SLOT-VALUE cannot generally be optimized.


	Lawrence G. Mayka
	AT&T Bell Laboratories
	lgm@iexist.att.com

Standard disclaimer.

sboswell@sdcc13.ucsd.edu (....What Is?....) (06/27/91)

In article <LGM.91Jun18195405@cbnewsc.ATT.COM> lgm@cbnewsc.ATT.COM (lawrence.g.mayka) writes:
>In article <1991Jun17.210108.29347@Think.COM> barmar@think.com (Barry Margolin) writes:
>In article <ALANR.91Jun17130803@chopin.media-lab.media.mit.edu> alanr@chopin.media-lab.media.mit.edu (Alan Ruttenberg) writes:
>>(deftype C () '(or A B))
>>
>>(defmethod common ((instance C))
>> ...)
>>
>>This doesn't work. (can't find class C)
>>
>>My only two choices seem to be to either replicate the code, or to factor the
>>body of the definition of common into a defun which is called by both.
>
>If A and B have any ancestors in common you could define the method on a
>common ancestor, and then use (check-type instance 'C) to catch misuse.
>But that's also pretty inelegant.  

I'm having a similar problem.  I wrote an AVL tree in Lisp a few
months back using a 4-element list as my basic data structure (left,
data, height, right).  Now I'm trying to convert it to CLOS.  I
defined the methods with parameter specializers that make them take
my avl-tree class, but I need to be able to have "no avl-tree", which
I was implementing as "nil".  But of course none of the avl-tree
methods recognize the null stuff.  Is factoring the only way to
get my methods to recognize both avl-tree and null as valid instances
of avl-tree?  I tried (defclass avl-tree (null) blah blah blah) but
it didn't help.

If there is no really good solution to this, I'll be amazed, since
out of the OOP paradigms I've seen so far, CLOS has been the best.

Steve Boswell         | This opinion is distributed in the hopes that it
whatis@ucsd.edu       | will be useful, but WITHOUT ANY WARRANTY...
whatis@gnu.ai.mit.edu |
-- 
Steve Boswell         | This opinion is distributed in the hopes that it
whatis@ucsd.edu       | will be useful, but WITHOUT ANY WARRANTY...
whatis@gnu.ai.mit.edu |