[comp.lang.clos] Is CLOS Object-Oriented ???

marquard@rimfaxe.diku.dk (Morten Marquard) (11/15/90)

I have a question to all readers of this group:
    "Is CLOS Object-Oriented ???"

In "normal" object-oriented languages (SmallTalk, C++) an object can
exist alone. An object consist of a state and a set of methods, and
only the methods can change the state of the object.

In CLOS an object can be changed by a generic function, in spite of
the fact that the object does not "own" the generic function, eq. a
generic function can change the state of an object, without the object
itself knowing it is has been changed! I have diskussed this with
others, and a lot of people do not view CLOS as an object-oriented
language. I need some good arguments, please.

Thanks,

--Morten Marquard
(marquard@diku.dk)

gumby@Cygnus.COM (David Vinayak Wallace) (11/16/90)

   Date: 15 Nov 90 10:18:47 GMT
   From: marquard@rimfaxe.diku.dk (Morten Marquard)

   In "normal" object-oriented languages (SmallTalk, C++) an object can
   exist alone. An object consist of a state and a set of methods, and
   only the methods can change the state of the object.

   In CLOS an object can be changed by a generic function, in spite of
   the fact that the object does not "own" the generic function, eq. a
   generic function can change the state of an object, without the object
   itself knowing it is has been changed!

Could you please rephrase your question?  What does it mean to "own" a
method?  The actual method invoked by a generic function may be found
due to some search, but that is no different than the case of the
languages you cite.  The method ultimately selected still must have
been defined for the class or one of its parents.

If you mean that handlers are not all declared or defined lexically
within the definition of some class, well, personally I consider that
an advantage, but there are people (and languages) that can make a
strong argument that it's a bad idea.

					  I have diskussed this with
   others, and a lot of people do not view CLOS as an object-oriented
   language.

It's ironic that an arriviste language like C++ is considered
"normal."

sticklen@cps.msu.edu (Jon Sticklen) (11/16/90)

From article <GUMBY.90Nov15080506@Cygnus.COM>, by gumby@Cygnus.COM (David Vinayak Wallace):
> 
>    Date: 15 Nov 90 10:18:47 GMT
>    From: marquard@rimfaxe.diku.dk (Morten Marquard)
> 
>    In "normal" object-oriented languages (SmallTalk, C++) an object can
>    exist alone. An object consist of a state and a set of methods, and
>    only the methods can change the state of the object.
> 
>    In CLOS an object can be changed by a generic function, in spite of
>    the fact that the object does not "own" the generic function, eq. a
>    generic function can change the state of an object, without the object
>    itself knowing it is has been changed!
> 
> Could you please rephrase your question?  What does it mean to "own" a
> method?  The actual method invoked by a generic function may be found
> due to some search, but that is no different than the case of the
> languages you cite.  The method ultimately selected still must have
> been defined for the class or one of its parents.
> 
> If you mean that handlers are not all declared or defined lexically
> within the definition of some class, well, personally I consider that
> an advantage, but there are people (and languages) that can make a
> strong argument that it's a bad idea.
> 
> 					  I have diskussed this with
>    others, and a lot of people do not view CLOS as an object-oriented
>    language.
> 
> It's ironic that an arriviste language like C++ is considered
> "normal."


i think you are right about c++...

but i think the original poster is right to raise the issue about
"owning" methods. in clos, all the arguments to a generic function
determine what version of the function is going to be applicable. 
in more restrictive langues (like smalltalk of loops) only the first
arguement (the object arguemnt) determines which version to use. 
and that allows one to think of a class as owning (or inheriting
in a straight forward way) a method. 

the real difference is the programing model that is being used in the
two different viewpoints. in CLOS, the model does not really include
the notion of an object "owning" a method, but in loops especially,
that is the way that programming tend to view the world. 

the result is that in CLOS there is a lot more flexibity/power, but
in LOOPS (and other languages of the same ilk) there is a strong 
sense of a object centered programming paradigm. so the trade off is
more power for a harder to manage (and esp to learn) programming world
view.

its interesting to note that when CLOS was first going around, being
dreamed up, et al, that it was touted as an "implimentation language"
in which other OOP langues could be built. Ie, LOOPS, FLAVORS, et al
would be reimplimented in CLOS via their individual meta level protocols.
that does not seem to be happening...

	---jon---

gamin@ireq-robot.hydro.qc.ca (Martin Boyer) (11/16/90)

In article <1990Nov15.101847.26285@diku.dk>,
marquard@rimfaxe.diku.dk (Morten Marquard) writes:
>
>I have a question to all readers of this group:
>    "Is CLOS Object-Oriented ???"
>
>In "normal" object-oriented languages (SmallTalk, C++) an object can
>exist alone. An object consist of a state and a set of methods, and
>only the methods can change the state of the object.
>
>In CLOS an object can be changed by a generic function, in spite of
>the fact that the object does not "own" the generic function [...]

Almost two years ago, I translated some code from Flavors (no doubt
about this one being object-oriented?) to CLOS (well, PCL to be
precise).  I learned the following: if you don't want to know about
generic functions, just forget they exist or, even better, consider
them just as the set of methods sharing the same name.

Then I learned that generic functions "contain" all methods of the
same name and that they discriminate, based on the type of the
arguments, which method is called.

Now, think about it, how is that different from what Flavors used to
do?  The form

(send object message)

can be rewritten without any loss of information as

(message object)

The way I see it, what "send" used to do in Flavors (finding which
method to call and then calling it) is now done in CLOS by the generic
function.

Agreed, it *looks* like we are going back to the old way of doing
things, when functions had to look at the arguments type to decide
what to do with them.  Except that the programmer still writes
methods; all this generic function stuff is done internally.

Now, an example to demonstrate one of the reasons why this
function/object reversal is useful:

Consider the classic

(send square :draw-yourself)

and let's say we want to add some functionality by allowing an extra
argument to indicate where this square should be drawn:

(send square :draw-yourself :on-screen)
(send square :draw-yourself :on-printer)

In Flavors, one would have to re-write the draw-yourself method to
discriminate on the second argument, because the procedure depends on
it.  But wait!  isn't that what "send" was supposed to do in the first
place, discriminate on the first argument to find out which method to
use?  We now need 'draw-yourself' methods specialized on more than one
argument, the object and the medium (as if, in this case, the medium
IS the message :-)).

My conclusion is that methods cannot always be 'owned' by a single
object; if two objects interact, it may not be conceptually sound to
*decide* which object gets the top-level message to then send another
message to the second object.  Perhaps they should *both* receive the
message because the method to use depends on the characteristics of
*both* objects.  This, IMHO, is the major benefit from CLOS; in the
true spirit of OOP, modularity (methods specialized on multiple
arguments) and code re-use (no need for type discrimination inside
methods, for instance).

-- 
Martin Boyer                            mboyer@ireq-robot.hydro.qc.ca
Institut de recherche d'Hydro-Quebec    mboyer@ireq-robot.uucp
Varennes, QC, Canada   J3X 1S1
+1 514 652-8136

jay@wiley.uucp (Jay Nelson) (11/17/90)

In article <3904@s3.ireq.hydro.qc.ca> gamin@ireq-robot.hydro.qc.ca (Martin Boyer) writes:

>Now, think about it, how is that different from what Flavors used to
>do?  The form
>
>(send object message)
>
>can be rewritten without any loss of information as
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>
>(message object)
>
>The way I see it, what "send" used to do in Flavors (finding which
>method to call and then calling it) is now done in CLOS by the generic
>function.

We ran into an interesting problem the other day with CLOS.  We had
some code in Flavors that we were converting to CLOS.  We had two
classes: Class A contained information that should be updated and
Class B contained the name of the slot in Class A to change.  In
Flavors the code was:

  (setf (send class-b (send class-a slot-to-change)) new-value)

Under CLOS you need to say:

  (setf (#'(slot-to-change class-a) class-b) new-value)
         ^^^^^^^^^^^^^^
Which doesn't quite work.

The difference is that the protocol of "send" allows the message to be
derefenced, whereas CLOS doesn't.
Jay Nelson  (TRW)  jay@wilbur.coyote.trw.com

scott@wiley.uucp (Scott Simpson) (11/17/90)

In article <3904@s3.ireq.hydro.qc.ca> gamin@ireq-robot.hydro.qc.ca (Martin Boyer) writes:
>The way I see it, what "send" used to do in Flavors (finding which
>method to call and then calling it) is now done in CLOS by the generic
>function.
>
>Agreed, it *looks* like we are going back to the old way of doing
>things, when functions had to look at the arguments type to decide
>what to do with them.  Except that the programmer still writes
>methods; all this generic function stuff is done internally.

I thought they were the same too until someone at work came up with
this problem in Flavors:

	(setf (send self (send button :slot-to-change)) value)

What is happening is that (send button :slot-to-change) returns the
name of a slot to change and that slot is changed to VALUE on the
object SELF. How do you do this is CLOS?
Scott Simpson			TRW			scott@coyote.trw.com

pab@lucid.com (Peter Benson) (11/17/90)

In article <27443D49.2BE8@wilbur.coyote.trw.com> scott@wiley.uucp (Scott Simpson) writes:
   In article <3904@s3.ireq.hydro.qc.ca> gamin@ireq-robot.hydro.qc.ca (Martin Boyer) writes:
   >The way I see it, what "send" used to do in Flavors (finding which
   >method to call and then calling it) is now done in CLOS by the generic
   >function.
   >
   I thought they were the same too until someone at work came up with
   this problem in Flavors:

	   (setf (send self (send button :slot-to-change)) value)

   What is happening is that (send button :slot-to-change) returns the
   name of a slot to change and that slot is changed to VALUE on the
   object SELF. How do you do this is CLOS?

It's not a generic function doing it, but the designers of CLOS provided
slot-value for occasions like this.

(setf (slot-value self (slot-to-change button)) value)

-ptr-

konstan@elmer-fudd.berkeley.edu (Joe Konstan) (11/17/90)

In article <PAB.90Nov16151057@3-mile-island.lucid.com>, pab@lucid.com (Peter Benson)
writes:
|> 
|> In article <27443D49.2BE8@wilbur.coyote.trw.com> scott@wiley.uucp (Scott Simpson)
writes:
|>    I thought they were the same too until someone at work came up with
|>    this problem in Flavors:
|> 
|> 	   (setf (send self (send button :slot-to-change)) value)
|> 
|>    What is happening is that (send button :slot-to-change) returns the
|>    name of a slot to change and that slot is changed to VALUE on the
|>    object SELF. How do you do this is CLOS?
|> 
|> It's not a generic function doing it, but the designers of CLOS provided
|> slot-value for occasions like this.
|> 
|> (setf (slot-value self (slot-to-change button)) value)

Unfortunately, this is not an acceptable substitute in many situations.  Since
the setf method can have customized features (indeed, there does not even need
to be a slot defined to have a setf method) this hack won't work.

I agree that slot-value is a useful (if dangerous) feature, but it doesn't
take the place of the above case.  One bad (but functional) solution is:

	(eval `(setf (,(slot-to-change button) self) value))

Which forces run-time evaluation, but is semantically correct.  A simple macro
can hide this detail as follows:

	(defmacro setf-indirect (indirect object new-value)
             `(setf (,(eval indirect) ,object) ,new-value))

And this could be called as:

	(setf-indirect (slot-to-change button) self value)

I'm sure people could write this into nicer syntax, but this seems to be
the best approach to solving that problem for occasional use.  If
high-performance were an issue, I'd suggest storing a pointer to the
setf-method instead of the name of the slot.

Joe Konstan

phil@Neon.Stanford.EDU (Phil Stubblefield) (11/17/90)

In article <PAB.90Nov16151057@3-mile-island.lucid.com> pab@lucid.com
 (Peter Benson) writes:
>
>In article <27443D49.2BE8@wilbur.coyote.trw.com> scott@wiley.uucp
> (Scott Simpson) writes (reformatted, edits bracketed):
>   I thought they [Flavors SEND and CLOS generic functions] were the
>   same too until someone at work came up with this problem in
>   Flavors:
>
>	   (setf (send self (send button :slot-to-change)) value)
>
>   What is happening is that (send button :slot-to-change) returns the
>   name of a slot to change and that slot is changed to VALUE on the
>   object SELF. How do you do this is CLOS?
>
>It's not a generic function doing it, but the designers of CLOS provided
>slot-value for occasions like this.
>
>(setf (slot-value self (slot-to-change button)) value)

I think that a better solution is to change the functionality of the
BUTTON as follows:

  (funcall (accessor-for-change button) value self)

The button now knows the name of the relevant accessor function rather
than the name of the slot.  This approach has two advantages:

  1) It uses the existing accessor, allowing full generic function
     dispatch, unlike the (SETF SLOT-VALUE) case.

  2) It provides better information hiding, insulating BUTTON from the
     implementation details of SELF.


-- 

Phil Stubblefield                                Email:  phil@rpal.com
Rockwell Palo Alto Laboratory                    Phone:  (415) 325-7165

jwz@lucid.com (Jamie Zawinski) (11/18/90)

In article <39639@ucbvax.BERKELEY.EDU> konstan@elmer-fudd.berkeley.edu (Joe Konstan) wrote:
> 
> I agree that slot-value is a useful (if dangerous) feature, but it doesn't
> take the place of the above case.  One bad (but functional) solution is:
> 
> 	(eval `(setf (,(slot-to-change button) self) value))
> 
> Which forces run-time evaluation, but is semantically correct.  A simple macro
> can hide this detail as follows:
> 
> 	(defmacro setf-indirect (indirect object new-value)
>              `(setf (,(eval indirect) ,object) ,new-value))

Well actually I think you meant 

 	(defmacro setf-indirect (indirect object new-value)
          `(eval `(setf (,,indirect ,',object) ,',new-value)))

Your example calls EVAL on INDIRECT at macroexpand (compile) time instead of
expanding to (eval `(setf (,(slot-to-change button) self) value)).

But anyway, this isn't a bad idea just because it runs interpreted, but also
because EVAL spawns a new lexical environment;

     (let ((button (foo))
           (self (bar))
           (value (baz)))
       (setf-indirect (slot-to-change button) self value))

which expands to

     (let ((button (foo))
           (self (bar))
           (value (baz)))
       (eval `(setf (,(slot-to-change button) self) value)))

will not work because EVAL will not see the lexical bindings of SELF and VALUE.
This is why calling EVAL is almost always the wrong thing to do.

You could arrange for the list passed to EVAL to contain only constants, as in

    (eval `(setf (,(slot-to-change button) ',self) ',value))

but in this case, the call to EVAL is little more than a FUNCALL, and could be
avoided by clever use of FUNCALL and GET-SETF-METHOD.  Under the new standard,
there might be an easier way to do this using something like the #'(SETF FOO)
syntax; I'm not sure.

But all this considered, Phil Stubblefield's solution

	  (funcall (accessor-for-change button) value self)

is probably the best, and Flavors really did handle this situation much better
than CLOS.
		-- Jamie

jeff@aiai.ed.ac.uk (Jeff Dalton) (11/20/90)

In article <1990Nov15.101847.26285@diku.dk> marquard@rimfaxe.diku.dk (Morten Marquard) writes:

>                                        I have diskussed this with
>others, and a lot of people do not view CLOS as an object-oriented
>language. 

That's because a lot of people are ideologues.

There's almost a small industry involved in defining "object-
oriented".  Some people are trying to get non-object-oriented
languages in, while others are trying to get languages that aren't
"really" object-oriented out.  Most of the exclusive definitions
do excessive violence to the history of OOP.  (No one dares to
make Smalltalk not be object-oriented, but some people dare to
make languages that don't have classes or that use delegation
rather than inheritance not be object-oriented.)

Anyway, there is a trivial way in which CLOS is not an object-
oriented *language*.  CLOS isn't a language (it's a part of Common
Lisp), so _a fortiori_ it isn't an object-oriented language.

This looks too trivial to mention, but I think some of the other
potential objections to CLOS are just as trivial at heart.

>only the methods can change the state of the object.

Suppose I take an object-oriented language and add a new way to
modify the state of an object?  Does the language suddenly cease
to be object-oriented?  If this is the way you think, CLOS will
not be object-oriented, because one can do a SETF of SLOT-VALUE.

But, just as we can allow that CLOS is object-oriented even though
the whole language (Common Lisp) is not (this is the dual of CLOS
not being a language on its own), we can allow that CLOS is object-
oriented even though there are some "dubious" additional features
in the CLOS part of CL.

This gets us, I think, the more serious objections.

>In "normal" object-oriented languages (SmallTalk, C++) an object can
>exist alone. An object consist of a state and a set of methods, and
>only the methods can change the state of the object.

>In CLOS an object can be changed by a generic function, in spite of
>the fact that the object does not "own" the generic function, eq. a
>generic function can change the state of an object, without the object
>itself knowing it is has been changed!

It is not clear to me what it means for an object to "know" it has
been changed.  Its state will change, and the methods will see the
new state.  Is that not good enough?

As for methods not being "owned", suppose we forget about multi-
methods for the moment.  Then, except for questions of storage
efficiency, an object could contain all methods that could ever
be applied to it.  Can we agree that this is object-oriented?
I hope so.

For all objects of the same class, however, we may as well store all
the methods in one place.  We could store them all in the class,
indexed by message name -- or in something associated with the message
name, indexed by class.  Let's do the latter, and make the "something"
be a (generic) function that sends the corresponding message.

Note that these changes are straightforward, and it's hard for me at
least to see why they'd make the resulting system no longer be object-
oriented.  (Of course, arbitrary changes might make it cease to be
object-oriented, but these aren't arbitrary changes.)

Now we can make a further generalization.  The method is selected 
by looking at the class of the first argument to the (generic)
function.  Why not look at the other arguments too?  If we do that,
as CLOS does, we have multi-methods.

At this point, it is harder to think of the methods as being part of
the objects and of the objects as interpreting messages sent to them,
but it is still a fairly straightforward generalization of such a
system.  If this generalization makes CLOS not be object-oriented,
then I would still say CLOS minus multi-methods is object-oriented.
In my view, however, having this additional capability does not negate
the essentially object-oriented nature of CLOS (just as having ways
other than via methods to change the state did not).

-- jeff

lanning@parc.xerox.com (Stan Lanning) (11/21/90)

The argument is (roughly) that functions that are not "owned" by an
object may directly access the internal state of the object, and this
precludes CLOS from being considered an Object-Oriented language.

Well, as far as this argument goes, C++ isn't object oriented, either.
There are enough loopholes in the language that you can smash the
internals of anything.  Free uses of casts and/or union types gives you
access to anything.  CLOS, by supplying SLOT-VALUE, is just providing a
structured, portable loophole.

As for questions about the ownership of a method, again C++ isn't clean
either.  If you overload the "<<" operator for a class you define, what
class owns the definition?  Your class?  Or the stream class?  Neither?

--
-- smL

Stan Lanning				lanning@parc.xerox.com
Xerox PARC
3333 Coyote Hill Road
Palo Alto, CA  94304			  (415)494-4880
USA					Fax: (415)494-4777

lgm@cbnewsc.att.com (lawrence.g.mayka) (11/22/90)

In article <LANNING.90Nov20110947@archer.parc.xerox.com>, lanning@parc.xerox.com (Stan Lanning) writes:
> The argument is (roughly) that functions that are not "owned" by an
> object may directly access the internal state of the object, and this
> precludes CLOS from being considered an Object-Oriented language.

Even Smalltalk has instVar:at:.  SLOT-VALUE simply offers the sensible
convenience of symbolic slot names rather than numerical structure
offsets.


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

Standard disclaimer.

barmar@think.com (Barry Margolin) (11/25/90)

In article <27443D49.2BE8@wilbur.coyote.trw.com> scott@wiley.UUCP (Scott Simpson) writes:
>I thought they were the same too until someone at work came up with
>this problem in Flavors:
>
>	(setf (send self (send button :slot-to-change)) value)
>
>What is happening is that (send button :slot-to-change) returns the
>name of a slot to change and that slot is changed to VALUE on the
>object SELF. How do you do this is CLOS?

Unfortunately, the above isn't valid Flavors code (at least as far as my
Symbolics machine is concerned).  When I try to macroexpand it I get told
that SETF of SEND requires the message name to be a constant.

IMHO, the closest translation is:

(funcall (slot-change-function button) self value)

The SLOT-CHANGE-FUNCTION generic function would generally return a function
of the form #'(setf <slot-name>).
--
Barry Margolin, Thinking Machines Corp.

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