[Grace-core] Import statements

Lex Spoon lex at lexspoon.org
Tue Jun 4 06:00:32 PDT 2013


Conceptually, I would emphasize the concepts of "dependency" and
"dependency resolution". A dependency is a *partial specification* of
an artifact that some other artifact needs. Dependency resolution is
the algorithm for turning that partial specification into a specific
artifact.

There's an art to putting just the right information in a dependency
and nothing more. If you specify too little, then people will assemble
systems that yield no warnings and yet still don't work. If you
specify too much, then it becomes hard to change the software, because
it interlocks too rigidly.

To achieve the right balance, it is important to assume that there is
extra information outside the language to resolve dependencies. If you
assume that you must resolve directly from a Grace file to another
Grace file, with no other information, then the problem is
over-constrained  To make the problem tractable, go ahead and assume
that there is such a thing as a Grace installation with a standard
layout. Go ahead and assume that the user has set up a personal
imports path. Looking ahead, for bigger projects, go ahead and assume
that people work against some form of shared repository.

For the immediate problem you describe, Kim, I believe either or both
of the following would be more than adequate:

1. Assume that Grace code is installed into some form of local
workspace, and that the Grace tools are told where the root of that
workspace is. Instead of having people hack their import lines, have
them copy or symlink the standard code into their local workspace
directory.

2. Have the user supply a lookup path of directories that they want
the tools to use.


The immediate problem aside, I would call out a few mistakes that
people make over and over again in the design of dependency systems.
It is better to avoid any of the following in an "includes" or a
"depends on" line:

1. Version numbers. There are a host of problems with versioned
dependencies: they don't work well with diamond dependencies,
developers don't have version numbers for their local changes, and it
forces you to update files just to bump the version numbers. Note that
if you touch a file to bump a version, then that file also gets a new
version, making the problem worse. The popular Maven build system has
many superficial flaws, but it also has some deep and fundamental
flaws. Among them is that Maven includes version numbers in its
"depends on" lines.

2. Machine-specific paths, such as people's home directories. If you
do that, then you can't install the software twice in two different
locations, and you can't easily install the software on a second
machine.

3. URLs. You don't want your builds to make requests to third-party
Internet sites. That means you need some local resolution mechanism to
turn a "URL" into something on the local disk anyway. That, in turn,
means that they aren't really URLs any longer; they just abuse the URL
syntax. I see little benefit in using URL syntax for something that is
quite different from a URL.

3b. DNS names. I know it's an unpopular opinion, but I think the Java
convention is slightly wrong. It really should be "import
junit.Assert" rather than "import org.randomcompany.junit.Assert".
There's just one concept of "JUnit" in the world. Yes, there are many
versions of JUnit, and that's why you need dependency resolution, but
neither the "org" nor the "randomcompany" really help your resolution
algorithm. The key information is "junit", so that's what ought to be
in the dependency and nothing more.

Lex Spoon


More information about the Grace-core mailing list