[e-lang] Alternative E loader [patch]
Thomas Leonard
tal at it-innovation.soton.ac.uk
Fri Feb 19 07:45:34 PST 2010
On Thu, 2010-02-11 at 16:50 +0000, Thomas Leonard wrote:
> Hi all,
>
> The E documentation (e.g. the Walnut guide) suggests that .emaker files
> should be placed somewhere in classpath and then imported using
> <import:mypackage.myMaker>.
>
> 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).
I've extended my loader a bit now, and created a patch to include it in
the main E distribution:
git pull git://gitorious.org/~tal-itinnov/repo-roscidus/it-innovation.git eloader
The patch can be viewed in a browser here:
http://gitorious.org/~tal-itinnov/repo-roscidus/it-innovation/commit/b979de85d03d3104fe223624b1b4bac98612775c
The updoc shows some examples, but the main changes are:
- <this> imports relative to the whole module, not relative to the
directory. This means that you never need to give a module its own
loader explicitly.
- Each file gets its own scope, with a unique FQName and its own
traceln().
- Each loader has a getRoot/0 method which returns a read-only view of
the module's root directory. This is to allow modules to find resources
(icons, help text, etc) relative to their code.
If accepted, it could also be used by rune to load the main program.
This would allow all E programs to import emaker files from the same
directory without any extra configuration (e.g. rune -cpa ...).
In terms of speed, it is dramatically faster than <import>. This test
case imports "testMaker.emaker" 100 times using both methods:
def makeLoaderAuthor := <elang:interp.ELoaderAuthor>
def makeScope := <unsafe:org.erights.e.elang.scope.makeScope>
def makeTraceln := <unsafe:org.erights.e.elib.debug.makeTraceln>
def makeELoader := makeLoaderAuthor(makeScope, makeTraceln)
def <eloader> := makeELoader(<file:.>, [].asMap(), "test$")
def timeIt(cb) {
for x in 1..10 {
cb()
}
def start := timer.now()
for x in 1..100 {
cb()
}
def finish := timer.now()
println(`Took: ${finish-start} ms`)
}
timeIt(fn { <import:testMaker> } )
timeIt(fn { <eloader:testMaker> } )
The test file was just this:
if (1 =~ x :int) { 2 }
Using <import:testMaker> it took: 3237 ms
Using <eloader:testMaker> it took: 195 ms
Notes:
- The getRoot method allows emakers to discover their own location. If
this is a problem, we could replace it with "getTextWriter" and
"getOutputStream" instead.
- Rather than creating a whole new scope for each file, I just extend
safeScope. This avoids having to keep reloading things. I'm assuming
that safeScope's slots can be safely shared between files?
- I'm not sure I've understood E's Scope system correctly. My code seems
to work, but it might be unnecessarily complicated and/or fragile.
Thoughts?
--
Dr Thomas Leonard
IT Innovation Centre
2 Venture Road
Southampton
Hampshire SO16 7NP
Tel: +44 0 23 8076 0834
Fax: +44 0 23 8076 0833
mailto:tal at it-innovation.soton.ac.uk
http://www.it-innovation.soton.ac.uk
More information about the e-lang
mailing list