[e-lang] Module naming and identification

Lex Spoon lex at lexspoon.org
Wed Apr 15 13:56:33 EDT 2009


Okay, I have read the document fully now.  It is an exccellent start
at discussion for an important problem.  Sorry for the length of my
reply; some of these issues are old axes of mine.

One problem is completely unaddressed: cyclical references between
modules.  It should be considered how A and B can depend on each
other, because this is the common case for modules that are used just
to chunk up the code into reasonably small files.

Also, two problems should actually be separated out, IMHO.    First,
depending on an API version (DirectX 9) is different from depending
on a module version (Nvidia RasterBlaster 3.5.11).  Second, linking to
with a plugin, such as a Google Gadget, is enough different from
regular module linkup that it merits separate consideration.

Okay, for the actual content, I must say that I object to having
versioned dependencies directly in the module source code.  I've argued
against this earlier in theory.  Below I will sketch some concrete use
cases to flesh out that theory.  Given how problematic they are in
practice, an out of band mechanism looks better for matching
up compatible versions of all the modules.

That said, having static strong reference looks important for actual
deployment on the web.  I only object to putting these references
in the original source code.

This duality means you would normally want to have an extra step in
your deployment chain.  For local development, map module references
via the file system, and bless versions of modules simply by  
installing them
in the right place in the file system.  As much as I think a developer  
is crippling
themself not to use compilers and build tools, this means that  
developers
who are happy being crippled can happily just hit "refresh" in their  
browser
without needing to set up any kind of tool chain.

For deployment, there are a couple of easy choices.  The simplest is  
to bundle
up the entire app, complete with all dependencies, and stick it in a  
directory
whose name includes a hash of the entire app's content.   This  
approach means there
is still no compiler or other tool. Better, though, would be to scan  
the code for module
references and pick a specific version for each one.  Then, dump all  
of these
module references into a single JSON map going from module name to
module version.  This JSON map could be included in the initial app  
download,
and it can be consulted as part of the implementation of require().

Given this general scheme of deployment, it's an additional  
requirement that the
module references be statically analyzable.  That's not actually
very restrictive, though.  Here are three constructs that are  
statically analyzable but
still very flexible:

   - module_ref("a/b/c") constructs a module reference but does not yet
   use it.

   - require(some_ref) loads whatever some_ref refers to.  IThe  
argumentt must
   be a module reference created with module_ref.

   - require("a/b/c") is a short-hand for require(module_ref("a/b/c")).


Okay, so that leaves my principle objection: no versions in source
code.  To see where I am coming from, let me suppose we do
include versioned dependencies in the source code and consider
a few common scenarios.  Suppose A depends on B and is known
to work with B version 1.3.

   1. The author of B releases version 1.5, which is not backwards
   compatible but happens to still be okay for A.  In that case, B
   can't claim full support for all users of B 1.3.  Does this mean A's
   author has to update A's source code?  If so, then whenever one
   package is rereleased, there will be a cascade of other packages
   being released.  This is especially bad when you consider that
   bumping the dependency information of A is grounds for bumping
   A's own version number.

   2. Suppose B releases version 1.5 which is mostly backwards
   compatible.  However, it's not bug for bug compatible, and A
   accidentally depends on something it shouldn't have.  A is already
   released saying it works of B version 1.3 or later, though.  To
   support this kind of thing, it had better be that there is no notion
   of automatic backwards compatibility.  A needs to list every
   possible version it can work with.

   3. Suppose a third party makes a forked version of B and calls it
   version 1.3.ubuntu5.  A knows nothing about this version, and in
   fact its dependency on B claims not to be compatible with it.  Does  
the third
   party also need to fork A, just to change the dependency info?

   4. Suppose A is compatible with version B 1.4, but only if C  
version 1.5 is
   not simultaneously loaded.  IN that case, you have to stick to B 1.3.
   This can easily happen in JavaScript with all the monkey patching  
going on!
   How in the world is this kind of dependency to be reflected in A's  
source code?

   5. Suppose you have 100 modules all with versioned dependencies.
   What are the odds that these dependencies can be simultaneously
   satisfied?  Compare that to the odds that there is a working set of
   versions for all of them.

Considering things like this, the precise version number depended on
doesn't really seem like something A should put in the source code.
A's author isn't really in a position to say as soon as you consider
multiple independent software groups.

To contrast, an out-of-band distribution approach makes it all easy.   
Ideally,
you work within a real distribution.  Given the state of JavaScript  
today, what
you do instead is accumulate in the repository for A a blessed copy of  
all other
modules depended on.  This is not only practical, but most projects  
already
do it, anyway.

Lex



More information about the e-lang mailing list