[e-lang] Alternative E loader

Thomas Leonard tal at it-innovation.soton.ac.uk
Thu Feb 11 08:50:27 PST 2010

Hi all,

The E documentation (e.g. the Walnut guide) suggests that .emaker files
should be placed somewhere in classpath and then imported using

If I want to depend on someone else's library then presumably I'm
supposed to add their jar or directory to my classpath. However:

- The classpath is a global (process-wide) namespace, so their emakers
may override or conflict with existing ones.

- Their jar may also introduce other files that affect the whole process
(e.g. .safej files, giving their emakers access to unsafe Java code).

- I have to mess around with extra -cpa options in the launcher scripts
(which always has to be duplicated, to support Linux and Windows).

- I can't add extra modules at runtime.

- I can't depend on two libraries that use the same class names (e.g.
two different versions of the same library).

How is this normally handled? I tried adding a small loader of my own
that loads from a directory rather than from classpath:


For example, I have a module containing some test cases. These depend on
some sample services in a module called "airport" and on some core code
in a module called "gria". I have a launcher script that runs the tests
like this:

def makeScope := <unsafe:org.erights.e.elang.scope.makeScope>
def makeLoader := makeLoaderAuthor(makeScope)

# The main code gets access to itself through <gria>
def <gria> := makeLoader(<file:src/main/e/gria>, [ => <gria> ], "gria$")

# The airport sample services access the main code through <gria> and themselves as <airport>
def <airport> := makeLoader(<file:src/main/e/airport>, [ => <gria>, => <airport> ], "airport$")

# The tests get access to <gria> and the <airport> sample services
def <tests> := makeLoader(<file:src/test/e>, [ => <airport>, => <gria> ], "tests$")

# Run the tests...
<tests>.getWithBase("tests.e", privilegedScope.getState())

The first argument to makeLoader/3 is the directory with the code, the
second is a map of extra things to put in the scope of every loaded
emaker (here, loaders for the module's dependencies) and the third is
the fqnPrefix (needed by makeScope, though it doesn't seem to matter
what I use).

For example, an emaker in the tests module would import something from
the gria module using:

  def makeFoo := <gria:makeFoo>

rather than (as before):

  def makeFoo := <import:org.gria.makeFoo>

I also got it to put a <this> loader in every emaker's scope, which
allows importing from the same directory (or from sub-directories). This
seems to be quite convenient, and would also make it easier for new
users to get started because you can just put a second emaker file in
the same directory as your main code and import it, without messing with
your rune options.

(I'm not quite decided as to whether <this> should refer to the parent
directory of the file or to the root directory for the whole module)

As far as I can see, this solves my problems. I can add extra modules as
dependencies without modifying classpath, and at runtime if necessary.
Modules don't get to add .safej files or otherwise mess with the JVM, so
they're easier to audit.

Is there something like this already in the E library that I've missed?
Is this a sensible approach?

I was worried that a pure E loader might slow things down but, for
reasons I don't understand, my loader is faster than E's <import>! At
least, it is when running my tests (which were not designed to measure
performance, just to test the code). They take about 40s to run using
<import> and about 35s using the new system.

If I modify my loader to cache the result of each import (which is
slightly unsafe, given that DeepFrozen doesn't work on code) then this
drops to 30s, which is still slightly faster than E's <import> modified
to assume everything is deep-frozen (31s).

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