[e-lang] Designing the E module system (was: A thought on module systems)

Thomas Leonard tal at it-innovation.soton.ac.uk
Fri Sep 3 04:45:52 PDT 2010

On Fri, 2010-09-03 at 06:52 -0400, Kevin Reid wrote:
> On Aug 29, 2010, at 4:01, Thomas Leonard wrote:
> > On 29 August 2010 03:31, Kevin Reid <kpreid at switchb.org> wrote:
> >> I think this is an original thought I had about the problem of  
> >> modules/
> >> libraries:
> >>
> >>   A module (library) is a stateless unum.
> >>
> >> Therefore:
> >>
> >>   Module loading is obtaining a presence of the unum.
> >>
> >>   Module naming is long-term remote object naming.
> >>
> >>   Library versioning is an upgrade/protocol-compatibility problem.
> >
> > By the way, I implemented such a module loading scheme for the ebox  
> > demo:
> >
> >  http://0install.net/ebox.html
> Just to get *some* of my thoughts on the matter in writing so we can  
> maybe make some progress, I'm going to comment on what I see :
> > For example, the "ebox-edit" example application declares a dependency
> > on the "ebox-help" library like this:
> >
> >    <requires interface="http://0install.net/tests/ebox-help.xml">
> >      <environment insert="" name="help"/>
> >    </requires>
> This is good, naming libraries by URLs, and giving the client control  
> over how the library is made available. What does the insert=  
> parameter mean?

It's the directory within the package which contains the root of the E
module. It's confusing and badly named in the context of E modules (and
probably always ""), but in other contexts you might use it like this:

   <requires interface="http://repo.roscidus.com/java/openjdk-6-jre">
     <environment insert="bin" name="PATH"/>

to get the Java package's "bin" directory inserted into your $PATH. I
should probably have created a new element, but it was easier to
re-purpose the existing <environment> ;-)

> We should not use XML, because XML is designed for document markup,  
> and we have a better choice at hand; namely TermL. (Though there is no  
> formalized TermL feature serving the role of XML namespaces, yet.)

One nice thing about XML is that if you visit the URL in a web-browser
then an XSLT stylesheet formats it as HTML for you.

> > This causes a loader for the library to be added to ebox-edit's
> > environment (Scope), so that it can import things using e.g.
> >
> >  def makeHelp := <help:makeHelp>
> Does <help> necessarily expose every file in the module as an  
> importable item? It should be possible for a module to have private  
> components, so that its public interface is well-defined.

You could modify it to pass <help>.getPublicAPI() instead of just <help>
to users of the package. But without DeepFrozen that has issues of its

Another option is to split out the API into a separate directory and
depend on it using:

  <environment insert="api" name="help"/>

Then, help's public API could depend in turn on code in the "impl"
directory. Seems a bit heavy-weight though.

> What about the module's access to itself? In particular, a module  
> should have a reference to its own file tree (as in the <resource>  
> loader), or a customizable file-to-object mapping thereof, so that it  
> can efficiently store binary data (e.g. images for a GUI library).

All modules get access to their own loader as <this>. You can use
<this>.getRoot() to get a read-only file object for the root directory
of the module.

By the way, the launcher scans all modules at start-up to check that
they don't contain symlinks. Would be nice if E's file objects handled
that more safely, though I can't see how to do it.

> > The "interface" URI is both the name of the library and a hint about
> > where to get information about it.
> Good.
> > Incompatible changes use a
> > different URI,
> Good.
> > while backwards-compatible changes just use a different
> > version number. Versions can be restricted like this:
> >
> >    <requires interface="http://0install.net/tests/ebox-help.xml">
> >      <environment insert="" name="help"/>
> >      <version not-before='1.0' before='2.0'/>
> >    </requires>
> What is the grammar and ordering of version numbers?

Version := DottedList ("-" Modifier? DottedList?)*
DottedList := (Integer ("." Integer)*)
Modifier := "pre" | "rc" | "post"

See: http://0install.net/interface-spec.html#versions

> > Downloads get shared automatically, so that if two programs happen to
> > use the same version of the same library, then the library only gets
> > downloaded and stored on disk once.
> It is also important that if there is a diamond dependency
>    A requires B --> B requires D
>    A requires C --> C requires D
> then only one copy of D is loaded into memory, so that B and C have a  
> shared vocabulary of objects.

If two modules have dependencies with the same interface URI then it
selects a single version for both.

Satisfying all the version constraints in this case was challenging, but
it solves the problem by expressing all the version requirements as a
huge boolean expression and using a SAT solver to find the solution.
See: http://roscidus.com/desktop/node/954

Dr Thomas Leonard
IT Innovation Centre
2 Venture Road
Hampshire SO16 7NP

Tel: +44 0 23 8076 0834
Fax: +44 0 23 8076 0833
mailto:tal at it-innovation.soton.ac.uk

More information about the e-lang mailing list