Helma Logo
main list history
previous version  overview  next version

Version 2 by hannes on 21. May 2008, 22:24

This page will eventually replace is a rewrite of the original Helma wiki page *Modules and Scopes in Helma NG*.

One rather annoying shortcoming of the JavaScript language is its lack of support for dealing with complex, large applications. This problem spans over several aspects of the language, from the way you get the code (no standard import feature as part of the language itself) to what the language does with the code (dumping it into one global scope, that is). It seems like this has forced every JavaScript library developer to come up with his or her own modularization tricks. And while some of these seem to work well enough, managing tangled namespaces by hand is not really most people's idea of fun.

In Helma, a JavaScript web application framework that started life in 1998, we had came up with a scheme that puts the code of every object into a separate directory. While it was possible to build some rather big applications using this approach, it could also result in unclear application structure, and it is often confusing for people who know JavaScript but are new to Helma.

When I started work on Helma 2 a few years ago, one goal was to get rid of the rigid code structure in Helma 1. But soon it became clear that while it was easy to add features to import and evaluate scripts and libraries, JavaScript's insistence on dumping everything into the same scope would make writing and managing code a nightmare. Thus I gave up on Helma 2, at least until I found out how to do it right.

It was when I started experimenting with Python that I learned how easy and unobtrusive *modules could work|http://www.effbot.org/zone/import-confusion.htm*. In Python, scripts never step on each other's toes. You just import what you need into whatever namespace you want and that's it. I started thinking about how this could be done in JavaScript. What got me thinking was a feature of *Rhino|http://www.mozilla.org/rhino/* (the JavaScript engine we're using, written in Java and hosted by the Mozilla Foundation) that allows *multiple scopes to share one scope for common read-only variables|http://www.mozilla.org/rhino/scopes.html#sharingscopes*. This is done by setting the parent scope of the multiple scopes to null (normally it would be the global scope) and instead set its prototype to the shared scope:

  var threadScope = new Object();
  threadScope.__parent__ = null;
  threadScope.__proto__ = sharedScope;

The nice thing about this is that you basically get a new top level scope - the scope where top level stuff and variables missing a var declaration get allocated - but it inherits from the shared scope through the prototype chain. When you give each script its own top level scope, the need to hide and wrap things into artificial namespaces to keep them colliding with things from other files suddenly goes away. This would have been good enough, but it was only when I realized that this also makes imported modules local to the importing code that I realized I had found the solution to the problems that had blocked Helma 2.