[comp.lang.clos] CLOS Private Methods

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