From: jeff@aiai.edinburgh.ac.uk (Jeff Dalton)
Subject: Re: CLOS Stylistic Questions -- Program Structuring
Organization: The Ohio State University Department of Computer and Information Science
Date: Mon, 17 Aug 1992 11:24:56 GMT

> >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.

> >        A second alternative (which I've been using) is to create a 
> >        "header" file with all of the needed declarations and
> >        definitions.  This includes "empty" defclasses (no contents, 
> >        just the class name and superclass names), macro definitions,
> >        and some defgenerics and proclamations.  

Modularity will often lead to there being several header files.
Then there will be files of macros, etc.  You also may have macros
that depend on other macros (suppose you define an extend-syntax
as used in some Schemes).  

(BTW, C programming, which involves extensive use of header files,
also tends to involve makefiles.)

> >        The advantage of this approach is that load/compile order,
> >        after loading this header, is unimportant.  A disadvantage is
> >        that each class gets defined and redefined (eliciting regular
> >        warnings from some compilers such as Lucid) which I imagine is
> >        not very efficient.

If you always write systems that follow a simple pattern, then
you can use a simple version of defsystem.

> 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.)

> 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?

> >2.  Subclasses in new packages 
> >
> >        ...[handling packages]...
> >        It seems that there are a few options, and I'm interested in
> >        which ones other people tend to use:
> >
> >        a)  Forget the modularity, just use a single package
> >     	   Perhaps an ugly solution, but it codes and debugs
> >     	   easily.
> >
> >        b)  Compromise the modularity and export the slot names, etc.
> >     	   Also ugly, but relatively simple.
> >
> >        c)  Use the :: naming withing the SPECIAL-AGENT 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 too think that the best solution is d) as long as no name conflicts
> result.  Resort to c) for conflicting names.  a) and b) seem like
> pretty low quality options.

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.)

-- jd