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