From: doug@monet.ads.com (Doug Morgan)
Subject: Re: CLOS Stylistic Questions -- Program Structuring
Organization: Advanced Decision Systems, Mountain View, CA 94043, +1 (415)
	960-7300
Date: Mon, 17 Aug 1992 17:41:09 GMT

In article <4948.9208171124@subnode.aiai.ed.ac.uk> jeff@aiai.edinburgh.ac.uk (Jeff Dalton) writes:

> > >1.  Load/Compile order dependencies
> > >
> > >        Certain things need to be loaded before others can be loaded
> > >        or compiled.  For example, class definitions must occur before
> > >        the class name can be used as a method specializer.
> > >
> > >        One solution is to use some version of defsystem and to
> > >        carefully assure that the dependencies can be met on a
> > >        per-file basis (i.e., no circular dependencies between files).
> > 
> > This intricate solution seems tedious, hard to document, hard to
> > maintain.  Unfortunately, I bet this solution is the most common.
> 
> I think you're being a bit hard on defsystem.
> 
> Is it really so bad?  It shows the dependencies between files
> all in one place.  It allows you to partially recompile a system
> (recompiling only the files that need to be recompiled).  (Which
> might happen just because an error occurred in the middle of
> compiling all the files.)  And it means you don't have to write
> your own special-purpose functions for compiling and loading your
> system.
> 
> I don't see why it would be tedious, hard to document, or hard
> to maintain.

Defsystem is great and would be hard to live without.  I use defsystem
and the second alternative (below).  The problem with the above
solution by itself is just that defclasses and defmethods appear in
the same file.  When this happens, each addition of a method
specialized to a new or different class to any file can cause the
developer(s) to have to manually rearrange the defsystem dependencies.
Different developers working on the same baseline set of files come up
with different dependencies.  It can happen that a method can be added
that causes a cycle in the dependency graph so that no correct load
ordering even exists.  This is especially likely when independent
changes from multiple developers are merged into a new complete
system.  This sensitivity of load order to file contents (needless)
complicates integration of changes from multiple people.  That's why I
think it's "tedious, hard to document, or hard to maintain."

  ...
> 
> > package definitions
> > exports and imports
> 
> Why aren't the exports and imports part of the package definition?
> (They more or less have to be if you use defpackage.)

This is just my personal taste.  I simply prefer to have the
additional external symbols for a class be textually marked off in
some way.  I use separate files, but comments within a single
defpackage would also work fine.  Since all the export/imports are
loaded in a group, they are logically equivalent to one defpackage
with merged import/exports.  And since it's all just equivalent to
comments I can't justify it further.

> > For instance, utility macros would go before everything with
> > their own set of four file groups.
> 
> Why do you need four file groups just to define macros?

Suppose you do awful things and write macros using lots of classes and
generic functions?  Then you get the same load order problems as
before.  At the moment, this is hypothetical, but might have been
reasonable for some of the code we have written in the past.

> > >2.  Subclasses in new packages 
  ...
> >        d)  Specifically import the desired symbols into the
> >            SPECIAL-AGENT packages either as an import-from clause in
> >            the defpackage or with an import call
> >     	   This seems like the best solution I've found.  I
> >     	   imagine it would also be pretty easy to design
> >     	   standard :import-from clauses for packages so all
> >     	   children of AGENT in other packages would use the same
> >     	   clause.
  ...
> I don't think it works very well to have a separate package for
> each class.  A separtate package for a group of related classes
> would usually work better, because otherwise the package structure
> gets too complex.  You also tend to start referring to internal
> names (by using "::" or by importing them), which violates the
> modularity of your packages, or else exporting names that should
> really be internal, thus violating the modularity of your class
> definitions.
> 
> The problem is that you want some names to be available only to
> certain packages (the ones that define subclasses) but Common Lisp
> provides only "available to everyone" (exported) and "available to no
> one" (not exported).  I'm not sure there is a very good solution to
> this in general, but the problem can be avoided when there is a group
> of related classes that can be considered as a single "service".  (Eg,
> if you want to provide a graphics service, you might have several
> class definitions in the "GRAPHICS" package.)

I completely agree with your comments.  A package per class is almost
never a good idea.  Classes almost always form systems of related
classes that are a much more natural target for a package.  I thought
of the original question more as "what do you do when you want a
subclass to be outside of the natural package of the superclass?"  I
suspect that this would hardly ever be a desireable thing to do, but
if you ever do want to do it, d) still seems the way to go.

> -- jd

doug