Helma Logo
main list history
previous version  overview  next version

Version 14 by hannes on 16. April 2008, 00:21

The include() function javascript import features in Helma 2 tries try to loosely imitate the *semantics of python's import statement|http://www.effbot.org/zone/import-confusion.htm* in order to allow applications to be written in a truly modular way. These are some The magic of the design goals:python is that a script never has to do anything special in order to avoid name clashes with other scripts, because every script lives in its one top level scope by default.

* By default, the include() function loads scripts into separate scopes matching the library's script name.To sum it up:
* The scope name can be overridden by passing a second argument to the include() function.
* Never is a library imported into the top level scope.
* If a library is imported into a scope that alreay is defined in the current script's code, the previous value is overwritten.
* Imported libraries are local to the script that imported them (which is possible because the script lives itself in its own scope).
* (If the same library is imported from different scripts within one application (possibly using different scope names), only one version of the library is instanciated and shared among the importing scripts.)?
* Imported libraries are aware of their location so they can use relative path names for local imports and references to other resources.

A simplistic implementation of most of # You don't have to use any special Javascript syntax to denote a namespace. Just use the behaviour described above in the Rhino shell may look like this:name/location of your script file.
# Yet hardly possible to produce a name collision, as each script lives in its own scope.
# Since scripts live in their own scope imported scripts are only visible to the scripts that imported them.

=== Implementation

Helma 2 implements this by using a <a href="http://www.mozilla.org/rhino/scopes.html#sharingscopes">separate top-level scope</a> for each loaded script file, using a shared top-level scope as prototype. A simplistic implementation of most of the behaviour described above in the Rhino shell may look like this:

  // set reference to global object
  var __global__ = __global__ || this;
  
  function include(script, as) {
    var scope = new Object();
    scope.__parent__ = null;
    scope.__proto__ = __global__;
    // scope is now a top level scope that inherits
    // from the global, shared top level scope
    scope.load(script);
    this[as] = scope;
  }

Of course, Helma 2 also takes care of script reloading and stuff, and the shared module scope is really a per-thread scoe that uses another scope for the really shared stuff.

=== Example

Suppose there is a Javascript file called <code>helma/database.js</code> with the following content:

  function getConnection(...) {
      ....
  }
  
  function Connection(...) {
      ...
  }
  
  function Query(...) {
      ...
  }

<dl>
<dt><b>importModule("helma.db")</b></dt>
<dd>Makes the functions defined in helma/database.js available in the current scope as
  helma.database.getConnection()
  helma.database.Connection()
  helma.database.Query()
</dd>
<dt><b>importModuleAs("helma.db", "db")</b></dt>
<dd>Makes the functions defined in helma/database.js available in the current scope as
  db.getConnection()
  db.Connection()
  db.Query()
</dd>
<dt><b>importFromModule("helma.db", "getConnection", "Query")</b></dt>
<dd>Makes the functions defined in helma/database.js available in the current scope as
  getConnection()
  Query()
</dd>
</dl>

Note that the functions in helma/database.js do not care in which namespace they are loaded. They only see what is defined in their local file, and in the global scope shared by all modules. The scope that loaded the module is absolutely invisible to the loaded module!

     removed
     added