barmar@think.com (Barry Margolin) (06/24/91)
[I've redirected followups to comp.lang.clos.] In article <20905@sdcc6.ucsd.edu> sboswell@sdcc13.ucsd.edu (....What Is?....) writes: >How do I make a CLOS method private, so it can only be called by >other methods in the same class? In CLOS, methods are not "in" a class, so there's no notion of methods being "in the same class". Generic functions invoke methods when the argument types match the parameter specializers (note the plural). In general, CLOS doesn't try to implement any information hiding. SLOT-VALUE, WITH-SLOTS, and WITH-ACCESSORS can be used anywhere (even in ordinary functions rather than methods). As with the rest of Common Lisp, the onus is on the programmer to establish and follow programming conventions, rather than having them be enforced by the language. -- Barry Margolin, Thinking Machines Corp. barmar@think.com {uunet,harvard}!think!barmar
lgm@cbnewsc.ATT.COM (lawrence.g.mayka) (06/26/91)
In article <1991Jun24.040141.27435@Think.COM> barmar@think.com (Barry Margolin) writes:
In general, CLOS doesn't try to implement any information hiding.
SLOT-VALUE, WITH-SLOTS, and WITH-ACCESSORS can be used anywhere (even in
ordinary functions rather than methods). As with the rest of Common Lisp,
the onus is on the programmer to establish and follow programming
conventions, rather than having them be enforced by the language.
The Common Lisp package system can be used for namespace partitioning
(but is essentially orthogonal to CLOS). Symbols - including class
names, generic function names, and slot names - typically belong to a
particular package, and cannot be referenced outside that package
except through explicit programmer action such as importation or use
of a package prefix. Typically, however, Common Lisp programmers
define packages rather sparingly - for example, MY-APPLICATION and
MY-APPLICATION-INTERNALS rather than a package for every class.
Lawrence G. Mayka
AT&T Bell Laboratories
lgm@iexist.att.com
Standard disclaimer.
lgm@iexist.ATt.COM (Lawrence G. Mayka) (06/26/91)
Date: Wed, 26 Jun 1991 00:02 CDT From: Jon L White <jonl%kuwait@lucid.com> But as you say, common practice amongst Common Lisp programmers is to use packages sparingly -- perhaps too sparingly. I believe this is due to the "Fear of Packages", and long have wanted to write an expose on the use of the CL package facility; something with a title like, say, "Packages Unwrapped". As ever, the "Fear of <x>" stems not only from an "Ignorance of <x>" but also an "Ignorance of One's Ignorance of <x>" One potential difficulty in managing multiple packages is the lack of language and environment support for dynamic modification of string/symbol/package relationships. Given the read-time significance of these relationships, such rigidity is understandable; nevertheless, it implies potentially massive recompilation when such a change is necessary. For example, let's say I compiled my system in package MY-PKG without remembering to import symbol OTHER-PKG:SYM first. All references to SYM in my system are now incorrect. Some environments can offer to have MY-PKG:SYM and OTHER-PKG:SYM share the same value "cell," but even this does not correct all tests for EQ and the like. What would really be needed here is a tool that replaces all references to MY-PKG:SYM with OTHER-PKG:SYM *in the compiled code.* But I do not know of any Common Lisp environment that offers such a tool. Lawrence G. Mayka AT&T Bell Laboratories lgm@iexist.att.com Standard disclaimer.
jonl%kuwait@lucid.com (Jon L White) (06/26/91)
re: The Common Lisp package system can be used for namespace partitioning (but is essentially orthogonal to CLOS). Right. The main difficulty is talking with people who are primarily familiar with the more "conventional" concepts of Object-Oriented programming as "information hiding" is that "Encapsulation" is not a fully commensurate concept. This is especially true when one views functions/methods as being "owned" by classes, because such a view is crippling to the multi-method concept (and such a view is fostered by an inordinate emphasis on univariate "message passing" to the neglect of the more general "generic functions"). Once having broken this stranglehold -- that classes are the sine qua non of encapsulation -- then it is easier to talk about the kinds of encapsulation provided by generic-functions in CLOS and by packages in Common Lisp. Along this vein, I would recommend reading a paper by Dick Gabriel, myself, and Danny Bobrow which has been accepted for publication in a special Lisp issue of CACM later this year: "CLOS: Integrating Object-Oriented and Functional Programming". Although we don't focus in on encapsulation per se, we do try to clarify the position of the generic-function concept in the Object-Oriented paradigm -- so that univariate "message passing" isn't misunderstood as the only such paradigm. But as you say, common practice amongst Common Lisp programmers is to use packages sparingly -- perhaps too sparingly. I believe this is due to the "Fear of Packages", and long have wanted to write an expose on the use of the CL package facility; something with a title like, say, "Packages Unwrapped". As ever, the "Fear of <x>" stems not only from an "Ignorance of <x>" but also an "Ignorance of One's Ignorance of <x>" -- JonL --
konstan@elmer-fudd.berkeley.edu (Joe Konstan) (06/26/91)
Re: Encapsulation and fear of packages I think that the lack of encapsulation problem is more than merely a fear of packages. With CLOS, there are many cases where a useful functionality is unavailable unless you have (and can modify) the source code to a class and/or the methods which specialize on that class. For one example (from the paper _Developing a GUIDE Using Object-Oriented Programming_ by me and Lawrence A. Rowe to appear at this year's OOPSLA) take the classes HOUSE and BOAT. Logically, as a user of multiple inheritance, I would like to create a child class HOUSEBOAT that inherits from both. Methods defined for one or the other of the superclasses work fine as do methods completely overridden in the subclass. Let's take the example of the generic function CLEAN, though. (defmethod CLEAN ((self HOUSE)) (wash-windows self) (scrub-floors self)) (defmethod CLEAN ((self BOAT)) (scrape-barnacles self)) ;; I show my ignorance about boats The default behavior I want for HOUSEBOAT is to do both. I can't do this by not defining a method, since neither HOUSE not BOAT does a call-next-method and therefore only the first superclass will have its method called. I can't even write a method such as: (defmethod CLEAN ((self HOUSEBOAT)) (CLEAN (HOUSE self)) (CLEAN (BOAT self))) In fact, I not only have to add call-next-method into the CLEAN method for at least one superclass, but I may have to make other changes as well (perhaps HOUSE is a subclass of DWELLING and DWELLING has a CLEAN method HOUSE doesn't call.....) This type of problem is at the heart of what I consider a predisposition against encapsulation. I realize that metaclass hacking can get around almost any individual problem like this, and that clever coding can sometimes do so as well, but for the average CLOS user, these problems constitute a failure in encapsulation. As for the issue of packages, I think that the reason most Common Lisp programmers fear or avoid them is related to the nasty interaction they have with the reader and with compiled-versus-interpreted code. One recent problem I'd hoped to use packages to solve illustrates some of these problems. I wanted to have two packages, VIDEO and FAKE-VIDEO, which would export the same symbols (functions such as PLAY and state variables such as PLAYER-STATE) and of which only one package would be in use at a time (based on whether the hardware could support video). I found this to be a difficult enough problem so as to make it not worth pursuing far. When interpreted, I could load one set of code or the other, use that package, and then load the code that called the video successfully. But, there was no way to compile the code that called the video or even load it in advance since to compile or load that code it needed to resolve the package of the symbols and would create them locally if they weren't already imported. Similarly, it is frustrating that even an export call creates symbols in the current package (so that I end up using (defpackage foo (:exports "FOO-SYM-1" "FOO-SYM-2")) since putting symbols in there would create them in the current package). One solution would be to have some sort of external declaration such as (defpackage video-user (:external play player-status)) which would indicate that the symbols play and player-status should be resolved at use-time rather than compile or load-time. This is getting a bit away from CLOS, but the point I'm trying to make is that CLOS really doesn't have viable encapsulation and that packages, while they could be used for that, are awkward enough that most CL programmers don't use them much. So long as this is the case, application writers desiring encapsulation will likely avoid CLOS. Joe Konstan konstan@cs.berkeley.edu
barmar@think.com (Barry Margolin) (06/26/91)
In article <42474@ucbvax.BERKELEY.EDU> konstan@elmer-fudd.berkeley.edu (Joe Konstan) writes: >Re: Encapsulation and fear of packages > >I think that the lack of encapsulation problem is more than merely a fear of >packages. With CLOS, there are many cases where a useful functionality is >unavailable unless you have (and can modify) the source code to a class and/or >the methods which specialize on that class. For one example ... >(defmethod CLEAN ((self HOUSE)) > (wash-windows self) > (scrub-floors self)) > >(defmethod CLEAN ((self BOAT)) > (scrape-barnacles self)) ;; I show my ignorance about boats > >The default behavior I want for HOUSEBOAT is to do both. I can't do this by >not defining a method, since neither HOUSE not BOAT does a call-next-method >and therefore only the first superclass will have its method called. This indicates that above methods were misdesigned, or (to give the author the benefit of the doubt) they were designed to be used as leaf classes, not as mixins. In order to allow classes to be mixed together, the methods have to use (when (next-method-p) (call-next-method ...)) or be implemented as :before or :around methods (in which case you have to make sure there is a base class with a primary method). If the mixins are designed and documented properly, you shouldn't need the source code to use them. Unfortunately, there still isn't enough experience in the industry in proper design and documentation of OO components, so you end up with code like the above. -- Barry Margolin, Thinking Machines Corp. barmar@think.com {uunet,harvard}!think!barmar
rathke@is.informatik.uni-stuttgart.de (Christian Rathke) (06/26/91)
In article <1991Jun26.071539.8418@Think.COM> barmar@think.com (Barry Margolin) writes: In article <42474@ucbvax.BERKELEY.EDU> konstan@elmer-fudd.berkeley.edu (Joe Konstan) writes: >Re: Encapsulation and fear of packages > >I think that the lack of encapsulation problem is more than merely a fear of >packages. With CLOS, there are many cases where a useful functionality is >unavailable unless you have (and can modify) the source code to a class and/or >the methods which specialize on that class. For one example ... >(defmethod CLEAN ((self HOUSE)) > (wash-windows self) > (scrub-floors self)) > >(defmethod CLEAN ((self BOAT)) > (scrape-barnacles self)) ;; I show my ignorance about boats > >The default behavior I want for HOUSEBOAT is to do both. I can't do this by >not defining a method, since neither HOUSE not BOAT does a call-next-method >and therefore only the first superclass will have its method called. This indicates that above methods were misdesigned, or (to give the author the benefit of the doubt) they were designed to be used as leaf classes, not as mixins. In order to allow classes to be mixed together, the methods have to use (when (next-method-p) (call-next-method ...)) or be implemented as :before or :around methods (in which case you have to make sure there is a base class with a primary method). ... or use a method combination of type PROGN. If the mixins are designed and documented properly, you shouldn't need the source code to use them. Unfortunately, there still isn't enough experience in the industry in proper design and documentation of OO components, so you end up with code like the above. I think there is a more principle problem with designing and modularizing functionality (not only) in object-oriented programming. "Proper design" can try to but can never meet the requirement of anticipating all possible future uses. The CLEAN methods of neither HOUSE nor BOAT above were intended to be used in the HOUSEBOAT or a similar context. I can think of several possible fixes: As far as I can remember, LOOPS was using some mechanism to refer to the "fringe" methods of super-classes. One could also think of modifying the method combination type (probably more problems generated than solved) Finally, programming support for object-oriented systems could support the inspection (browsers, etc.) and modification of inherited information. -- Barry Margolin, Thinking Machines Corp. barmar@think.com {uunet,harvard}!think!barmar -Christian Rathke ============================================================================== Christian Rathke rathke@informatik.uni-stuttgart.de Institut fuer Informatik Universitaet Stuttgart Breitwiesenstrasse 20-22 W-7000 Stuttgart 80 Tel.: (+49 711) 7816-436 ==============================================================================
jack@ircam.fr (06/27/91)
In article <1991Jun24.040141.27435@Think.COM> barmar@think.com writes: >[I've redirected followups to comp.lang.clos.] > >In article <20905@sdcc6.ucsd.edu> sboswell@sdcc13.ucsd.edu (....What Is?....) writes: >>How do I make a CLOS method private, so it can only be called by >>other methods in the same class? > >In CLOS, methods are not "in" a class, so there's no notion of methods >being "in the same class". Generic functions invoke methods when the >argument types match the parameter specializers (note the plural). I've implemented a very simple system called PFOOL on top of CLOS. In PFOOL, the dispatching of a generic function to the method depends only on the first argument (called the receiver of the message (guess where it comes from ?)), so methods really belong to some class. Inside the body of a method, the receiver can access to its slots which are all private by default. If you want some object's fields to be read and/or write accessible, you have to provide methods for it. I guess implementing private methods in PFOOL (or using a similar scheme) should not be too difficult. >In general, CLOS doesn't try to implement any information hiding. >SLOT-VALUE, WITH-SLOTS, and WITH-ACCESSORS can be used anywhere (even in >ordinary functions rather than methods). As with the rest of Common Lisp, >the onus is on the programmer to establish and follow programming >conventions, rather than having them be enforced by the language. An "Object Oriented system without any information hiding" !? That seems quite strange (coming from other object systems) ! (Except if you think of CLOS as an assembly language to make higher-level languages) Getting a good style takes a lot of years with a "good" language. It takes even more with "bad" languages. Remember the difference between programs written in Basic and programs written in PASCAL. What about teaching lisp with "goto" instructions instead of structured loops? >Barry Margolin, Thinking Machines Corp. Jacques Duthen (apologize for the English, I need more years...)
davis@sun4-64.ilog.fr (Harley Davis) (06/27/91)
In article <1991Jun26.202149.1346@ircam.fr> jack@ircam.fr writes:
An "Object Oriented system without any information hiding" !?
That seems quite strange (coming from other object systems) !
(Except if you think of CLOS as an assembly language to make higher-level
languages)
Getting a good style takes a lot of years with a "good"
language. It takes even more with "bad" languages. Remember the difference
between programs written in Basic and programs written in PASCAL.
What about teaching lisp with "goto" instructions instead of structured loops?
Perhaps it seems strange coming from C++. However, with a few
exceptions, Lisp-based object systems are typically considered
mechanisms for building abstractions. Information hiding is provided
by orthogonal facilities which work for the non-object-oriented parts
of the language. In CommonLisp, this is done with packages. In
EuLisp and Le-Lisp, this is done with modules. So I don't think this
depends on a view of Lisp as an assembly language, and even if you
take this view, which has some merit, the analogy needn't be extended
to using GOTOs instead of structured programming features.
-- Harley Davis
--
------------------------------------------------------------------------------
nom: Harley Davis ILOG S.A.
net: davis@ilog.fr 2 Avenue Gallie'ni, BP 85
tel: (33 1) 46 63 66 66 94253 Gentilly Cedex, France
jonl%kuwait@lucid.com (Jon L White) (06/28/91)
re: An "Object Oriented system without any information hiding" !? That's a gross overstatement (despite Harley's acquiescence for the sake of argument.) It may be belaboring the point, but it needs to be said again: In a world with the kind of dynamism of Common Lisp, "information hiding" and "Encapsulation" have to mean different things. For example, "information hiding" in the context of the "other" object systems often means nothing more than lexical scoping. You are aware of the lexical constructs in Common Lisp, no? But suppose for example that a language like C embodied the notion of first-class symbol-tables available at runtime -- with perhaps an access protocol such as you might use in typical C debuggers. What would "information hiding" mean then? Everything is inherently accessible, albeit by a few lines of symbol-table programming rather than a purely static token. With the dynamism of Lisp, a notion of module-spearated names is not a bad idea. Common Lisp packages is one cut at this approach; it leaves as much as possible still inherently accessible, but with some suggested "safe" protocols. Some other kindred approaches would cut out a lot of the runtime accessibilies -- in pretty much the same way that most Common Lisp compilers cut out the actual symbol on compiled, lexically-local variables. But for a language with a full reflective power, you need that accessibility. -- JonL --
spector@mimsy.umd.edu (Lee Spector) (06/28/91)
In article <9106260502.AA11848@kuwait> jonl%kuwait@lucid.com (Jon L White) writes: >But as you say, common practice amongst Common Lisp programmers is to use >packages sparingly -- perhaps too sparingly. I believe this is due to the >"Fear of Packages", and long have wanted to write an expose on the use of >the CL package facility; something with a title like, say, "Packages >Unwrapped". As ever, the "Fear of <x>" stems not only from an "Ignorance >of <x>" but also an "Ignorance of One's Ignorance of <x>" > >-- JonL - I'd simply like to incourage JonL or anyone else to write package system tips, and to post them here, in comp.lang.lisp, or in any obtainable, published source. Though I have read Steele on packages many times, I nonetheless sometimes have nasty, time-consuming fights with the package system. There have already been a couple of helpful followups on this, but a more comprehensive guide would be really nice. Nothing else in CL/CLOS has ever caused me such grief... -Lee (spector@cs.umd.edu)
ksh@ai.mit.edu (K. Shane Hartman) (06/28/91)
In article <11744@ifi.informatik.uni-stuttgart.de> rathke@is.informatik.uni-stuttgart.de (Christian Rathke) writes: Path: ai-lab!snorkelwacker.mit.edu!ira.uka.de!ifistg!rathke@is.informatik.uni-stuttgart.de From: rathke@is.informatik.uni-stuttgart.de (Christian Rathke) Newsgroups: comp.lang.clos Date: 26 Jun 91 10:18:26 GMT Sender: news@ifistg.uucp Lines: 68 In article <42474@ucbvax.BERKELEY.EDU> konstan@elmer-fudd.berkeley.edu (Joe Konstan) writes: >Re: Encapsulation and fear of packages > >I think that the lack of encapsulation problem is more than merely a fear of >packages. With CLOS, there are many cases where a useful functionality is >unavailable unless you have (and can modify) the source code to a class and/or >the methods which specialize on that class. For one example ... Reusing code in this manner without the source is pinheaded anyway. Shane Hartman