js2py and Jsmod

183 views
Skip to first unread message

Jonathan Fine

unread,
Apr 30, 2010, 1:55:22 AM4/30/10
to JavaScript for Python programmers
Hello

JavaScript doesn't have anything like Python modules and, perhaps as a consequence, it doesn't have a standard library.  For me this is one of the pressing tasks in JavaScript development.

To address this problem I've created Jsmod, and I'd like the py2js enthusiasts to consider adopting it.  I think it's about as production ready as py2js is, so it not being completely finished shouldn't be such a problem.
    http://bitbucket.org/jfine/jsmod/

I'm thinking that my creating a Jsmod branch of the py2js core library might be a good idea, both for Jsmod and also for js2py.

--
Jonathan

--
You received this message because you are subscribed to the Google Groups "JavaScript for Python programmers" group.
To post to this group, send an email to js...@googlegroups.com.
To unsubscribe from this group, send email to js4py+un...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/js4py?hl=en-GB.

Peter Rust

unread,
Apr 30, 2010, 3:23:02 AM4/30/10
to js...@googlegroups.com

Jonathan,

 

I’d like to hear about the benefits of JSMOD’s syntax, as compared to my $import and $from functions. From what I can tell, both do basically the same thing – both use eval() to generate a bunch of “var” statements to import a number of items into the current scope. It seem to me that the main difference is syntax.

 

Import Syntax

The $import / $from syntax maps more closely to the python functions (which IMO is important for py2js), plus it is more explicit and command-like – you’re running a function to import things, rather than declaring a list of imports. With JSMOD, the actual command that does the imports comes later – “eval(__)” – which doesn’t seem as intuitive...

 

Module Declaration Syntax

With JSMOD, you set the name to a string and let JSMOD implicitly save your module to an inner object. Again, with the $import / $from syntax, things more explicit. It’s being done the same way many Javascript libraries handle namespaces – simply using nested objects: “$import.my_module = …” and “$import.my_module.my_submodule = …”.

 

The only advantage of the indirect syntax that I can see (please let me know if there are more) is preventing users of the libraries from messing things up for others. With the $import/$from syntax, one piece of code could set $import.foo = null; and thereby screw up another piece of code that was going to import foo later and now can’t. However, we’re talking about two pieces of script running on the same page – there are much easier ways scripts can mess each other up, like blowing away the global $import or JSMOD object, for instance. It’s simply not possible to totally sandbox client-side scripts to protect them from each-other.

 

If you’re thinking about server-side Javascript, in CommonJS there’s a require function for that – but it’s not a good fit for client-side Javascript.

 

For client-side javascript, the most important thing module authors can do is wrap their stuff in an anonymous function and only expose the functions and classes that they want to expose. IMO, the amount of additional sandboxing you get from hiding the imports in an inner object really isn’t that much – and (again IMO) the less intuitive syntax isn’t worth the slight gain in sandboxing.

 

-- peter

Jonathan Fine

unread,
Apr 30, 2010, 6:21:35 AM4/30/10
to js...@googlegroups.com
Good question, Peter.  I'll reply about 8 hours from now.  Thank you for mentioning CommonJS.

From your very good question I can extract a brief answer.  I want something consistent with CommonJS but which is a good fit for client side programming.

Peter Rust

unread,
Apr 30, 2010, 12:16:24 PM4/30/10
to js...@googlegroups.com

> I want something consistent with CommonJS

> but which is a good fit for client side programming

FYI: The abandoned ECMAScript 4 spec specified “Modularity, name hiding and library construction” by packages and namespaces. While many ECMAScript 4 ideas were brought forward to the ECMAScript 6 specification, according to wikipedia, the packages and namespaces were not.

 

While the CommonJS spec both (synchronously) loads the desired module and imports it into the current scope – and this is what Python does and I think it’s wise for a server-side system – the ECMAScript 4 spec only focuses on the latter (importing variables into the current scope). Because of the latency of client-side connections and the variety of loading and packaging mechanisms already available, I think it’s wise to separate concerns and let the loading be handled separately.

 

Note that the ECMAScript 4 spec is nicely declarative and clear. Declaring a module as part of a namespace looks like this:

 

    package org.ecmascript.experiment {

        internal var v;

    }

 

    package org.ecmascript.experiment {

        public function f(k) { v+= k; return v-1 }

    }

 

And importing f (and everything else in experiment) looks like this:

 

    import org.ecmascript.experiment.*

 

 

 

If we were to convert this into today’s Javascript, declaring the module would look something like this:

 

    var org = or || {};

    org.ecmascript = org.ecmascript || {};

    org.ecmascript.experiment = (function() {

        var v;

        function f(k) { v += k; return v-1 }

 

        return { f: f };

    })();

 

And importing would look something like this (using $import because import is a reserved word):

 

    eval($import('org.ecmascript.experiment.*'));

 

 

 

The CommonJS specification examples come with “Browser Sharable” versions, here’s the “protect the global namespace” version that handles everything inside a function require.install(). It looks like this:

//

// math.js

//

(function(){

 

    var mod = function(require,exports) {

 

        exports.add = function() {

            var sum = 0, i = 0, args = arguments, l = args.length;

            while (i < l) {

                sum += args[i++];

            }

            return sum;

        };

 

    };

 

    require.install ? require.install('math', mod) : mod(require, exports);

 

})();

 

Creating a 2nd module that uses the math module above looks like this:

//
// increment.js
//
(function(){
 
    var mod = function(require,exports) {
 
  var add = require('math').add;
  exports.increment = function(val) {
      return add(val, 1);
  };
 
    };
 
    require.install ? require.install('increment', mod) : mod(require, exports);
 
})();

 

Creating a program that uses the increment module above looks like this:

//
// program.js
//
var inc = require('increment').increment;
var a = 1;
inc(a); // 2

 

 

 

And here’s the de-facto standard of the web today, where each library hangs everything off their own global library object:

 

// define the library in a file called asdf.js
// first and last lines are boilerplate 
 
var LIB = LIB || {};
LIB.asdf = (function() {
 
    var exports={};
 
    var c = 1;
    exports.a = function() {
        return c;
    };
    exports.b = 2;
 
    return exports;
 
})();
 
// use the library in the browser
 
LIB.asdf.a();
 
// use the library on the server
 
require('asdf').LIB.asdf.a();
 
// Use the library on the server or in browser.
// A module dependent on asdf would need to 
// be written like this or something similar.
 
(require ? require('asdf') : window).LIB.asdf.a();

 

 

If we’re to promote an import mechanism that we’d like to have widespread acceptance, it seems it should at least be able to import from modules defined in the de-facto standard (from a library global object), even if it doesn’t export that way and doesn’t encourage module authors to write their modules in that way.

 

-- peter

Jonathan Fine

unread,
Apr 30, 2010, 2:05:34 PM4/30/10
to js...@googlegroups.com
Hello Peter

On Fri, Apr 30, 2010 at 8:23 AM, Peter Rust <pe...@cornerstonenw.com> wrote:

I’d like to hear about the benefits of JSMOD’s syntax, as compared to my $import and $from functions. From what I can tell, both do basically the same thing – both use eval() to generate a bunch of “var” statements to import a number of items into the current scope. It seem to me that the main difference is syntax.

What both approaches have in common is the eval of a dynamic string in order to place some variable declarations into the body of a function.  But there are differences, mainly related to control, scope and timing.
 

Import Syntax

The $import / $from syntax maps more closely to the python functions (which IMO is important for py2js), plus it is more explicit and command-like – you’re running a function to import things, rather than declaring a list of imports. With JSMOD, the actual command that does the imports comes later – “eval(__)” – which doesn’t seem as intuitive...

Python ordinarily imports modules from a nearby file system.  JavaScript ordinarily loads scripts (we can't yet talk about import) from a distant web server (the World wide web) and possibly from another domain (which had better be trusted, of course).

In Python import  is a statement that can appear anywhere in the file, even in functions.  (This is sometimes done to avoid problems due to circular imports.)

In browser JavaScript it is not possible to load and use code within a function call, except by using Ajax requests.  And the present security model means that users are rightly advised not to permit such request cross-domain.

Let's look at the following problem.  Suppose we load a function that maps module names to URLs (similar to the Python paths) and then we load a code that has dependencies, which 'makes imports'.

With Jsmod it is possible to dynamically determine what modules need to be imported, and to import them and then when all is ready, excute the body of the module.

There's an example of this (due to myself) at http://www.mathtran.org/editor/js/editor.js and the module sources are at http://www.mathtran.org/editor/js/editor.js.  (It uses an earlier version of Jsmod.)

This is, of course, not a good idea for high-volume pages web pages, but it's a great help when developing and testing locally.  It means that no special build process is required.
 

Module Declaration Syntax

With JSMOD, you set the name to a string and let JSMOD implicitly save your module to an inner object. Again, with the $import / $from syntax, things more explicit. It’s being done the same way many Javascript libraries handle namespaces – simply using nested objects: “$import.my_module = …” and “$import.my_module.my_submodule = …”.

In Python a 'top-level' assignment creates an attribute on the module object.  There's no way to do this in JavaScript (except as I recall using the rightly disapproved of 'with' statement) but writing m.member = value comes pretty close.

 

 The only advantage of the indirect syntax that I can see (please let me know if there are more) is preventing users of the libraries from messing things up for others. With the $import/$from syntax, one piece of code could set $import.foo = null; and thereby screw up another piece of code that was going to import foo later and now can’t. However, we’re talking about two pieces of script running on the same page – there are much easier ways scripts can mess each other up, like blowing away the global $import or JSMOD object, for instance. It’s simply not possible to totally sandbox client-side scripts to protect them from each-other.

There is a great deal that can be done, particularly if you are first to load.  You can create a highly complex function (which for example contains secret keys) and leave it at a particular location on JavaScript's global object.  Subsequent scripts can use the function, but they won't be able to look inside it.

This is something that can be done with JSMOD (providing you get to load first) but not with the scheme you suggest.

 If you’re thinking about server-side Javascript, in CommonJS there’s a require function for that – but it’s not a good fit for client-side Javascript.

As I said earlier today, Jsmod is I believe consistent both with CommonJS and with the needs of client-side JavaScript.

For client-side javascript, the most important thing module authors can do is wrap their stuff in an anonymous function and only expose the functions and classes that they want to expose. IMO, the amount of additional sandboxing you get from hiding the imports in an inner object really isn’t that much – and (again IMO) the less intuitive syntax isn’t worth the slight gain in sandboxing.


I've got quite used to the syntax and even, dare I say, quite like it.  There's a bit of a learning curve, just as there is for the if __name__ == '__main__' idiom.  However, as with Python, you can use the construct without exactly understanding how it works.

The above arguments are theoretical, but in the end it is a practical matter.  I think a Jsmod branch of the py2js core JavaScript might be more persuavive.

One final point.  According to Martelli's Nutshell book, "If a function contains an exec statement without explicit dictionaries the whole function slows down substantially. [...] because such an exex might cause any alteration at all to the function's namespace."  He then goes on to say that the same applies to from module import *.

I'm confident that the same applies to JavaScript.  The test function in py_builtins_tests.html will I'm sure suffer from this fault.  Thus, the performance will be poor because each time the function test is called the eval must be performed.

If you were to define a function wibble within the test function and say make it available as global then wibble will not have this problem.  But it you do that then you're adopting part of the JSMOD design.

I hope this helps.  It took me about a year to get my head around all these issues (and I still have some uncertainty about some of details).


Jonathan

Jonathan Fine

unread,
Apr 30, 2010, 2:08:21 PM4/30/10
to js...@googlegroups.com
Hello Peter

On Fri, Apr 30, 2010 at 5:16 PM, Peter Rust <pe...@cornerstonenw.com> wrote:

> I want something consistent with CommonJS

> but which is a good fit for client side programming

FYI: The abandoned ECMAScript 4 spec specified “Modularity, name hiding and library construction” by packages and namespaces. While many ECMAScript 4 ideas were brought forward to the ECMAScript 6 specification, according to wikipedia, the packages and namespaces were not.


Do you mind it we pick this topic up later?  I think my response to your previous message (which took about 90 minutes to write) is sufficient to allow the discussion to continue.


Jonathan
Reply all
Reply to author
Forward
0 new messages