[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: A Proposal for Environments in Scheme



This is a reply to Pavel's message of almost two weeks ago proposing the
use of first class environments to define modules.  Sorry to take so long
replying, my mailbox runeth over...


Overall, I think that the idea of trying to standardize the environment
manipulation functions across the implementations that support them is a good
idea, although I am not sure that this belongs in the definition of the language.
However, after having spent a good deal of time lately thinking about modules, I
have come to the conclusion that implementing them using first class
environments directly is probably not the right thing.


First some comments on the proposal:


  MAKE-ENVIRONMENT <id> <parent> ...				[Procedure]

Unrestricted multiple inheritence is a TERRIBLE idea.  It breaks just about
every tenet of modularity that I can think of.  Inheriting from two parent
environments creates a dependence between the two parents where none previously
existed.  Making a safe change to either of the parents now requires detailed
knowledge of the other parent.  The presence of multiple inheritence encourages
the building of "brittle" systems, whereas a good module system should encourage
the building of robust systems.


   In addition to these procedures, We propose a change to the meanings of
   identifiers whose names include colons:


Using qualified names as you advocate tends to decrease the modularity of
systems by wiring in a particular organization of modules.  A qualified name
such as MATH:SQRT specifies both that you want a square root function and that
you want if from the MATH module.  Most of the time you would like to specify
that you want a square root function and you don't care where it comes from. The
place it comes from should be specified separately.  Also, it is impossible to
abstract over, or shadow a qualified name.


   THE SYNTAX AND SEMANTICS OF FILES


I share JINX's reservations about making files "absolute" rather than
"relative".  As a general rule I believe that all "global" or "absolute"
constructs are unmodular (with the possible exception of symbols).


  THE INITIAL ENVIRONMENT STRUCTURE


I think this is on the right track but I would like to see the procedures
related to each data type in their own separate modules.  For example, there
should be a separate module that defines the vector operations.  This is very
subjective though.


  (EXPORT <expression> <export-spec>+)


I don't understand something here.  If I export a variable X into an environment
E, does X act as if it was directly defined in E, or does it act as if it was
inherited by E?  In other words, what happens if I now DEFINE X in E?  Is a new
X created, or is the other one set!.  

Again I beleive that the EXPORT form is basically unmodular.  It specifies both
that a value is produced by this module, and where this value should be put.

As a concrete example of where this type of thing hurts you, suppose that an
environment had become trashed and I wished to re-create it from scratch.  I
would like to throw away the old environment, create a new one, and load into it
the file(s) that define the contents of the environent.  However, in order to
get the values that were exported into the environment, I must also load all the
files that exported into it.  This is likely to cause totally unrelated values
to be reloaded, possibly causing even more trouble.



Overall, I think that first class environments have their place, but the style
of modularization they encourage has some problems.  The kind of module system I
would like to see separately specifies: (1) what values a module needs, (2)
where those values come from, (3) what values a module produces, and (4) where
those values go.  A construct with these properties already exists in Scheme in
the form of procedures.  Consider this procedure:

	(lambda (sqrt draw-line)
	   (define (foo) ...)
	   (define (bar) ...)
	   (list foo bar))

This "imports" two values (sqrt and draw-line) and "exports" two values (foo and
bar).  What values actually get imported is determined by the combination the
function is applied in.  What is done with those values is determined by what is
done with the values returned by the combination.  The "module" defines a
behavior that can be instantiated many times with different values imported and
exported each time.

I am in the process of designing a module system that is based on using
procedures as modules, but that tries to avoid some of the pitfalls of doing so.
For example, it tries to avoid specifying large numbers of inputs and outputs
positionally since doing so tends to be tricky and error prone.  I have run into
some difficult issues that need to be resolved, but I hope to have a detailed
description ready in a couple of months.  The system I have in mind is somewhat
similar to the ML module system that Jonathan described.

The point I would like to emphasize is that a good module system should
encourage and facilitate a "clean" and "modular" style of programming.
Unfortunately, this can get pretty subjective so there may never be one system
that pleases everyone.

I hope you find these comments thought provoking and look forward to your reply.