Secureable Modules: "exports" vs "this"

103 views
Skip to first unread message

Ryan Dahl

unread,
Apr 10, 2009, 6:23:19 AM4/10/09
to serv...@googlegroups.com
Why not use "this" instead of "exports"? for example:

function require (__filename) {
return function ( ) { eval(File.read(__filename)); }( );
}

Aristid Breitkreuz

unread,
Apr 10, 2009, 6:42:55 AM4/10/09
to serv...@googlegroups.com
Ryan Dahl schrieb:

> Why not use "this" instead of "exports"? for example:
>
I like how "exports" is very explicit. If you read "exports.add =
function () ...", then you immediately know that it is an export. To
understand "this.add = ..." you need to read more context.


Aristid Breitkreuz

Ryan Dahl

unread,
Apr 10, 2009, 6:58:56 AM4/10/09
to serv...@googlegroups.com
> I like how "exports" is very explicit. If you read "exports.add =
> function () ...", then you immediately know that it is an export. To
> understand "this.add = ..." you need to read more context.

All context layers in javascript use this; why should the top level
context be different? Why introduce a new keyword. I'd rather view
module files as constructor functions for objects.

Also many browser scripts today can be immediately used with the
module system if "this" is used instead of "exports":
http://www.json.org/json2.js
http://jqueryjs.googlecode.com/files/jquery-1.3.2.js

Mark Miller

unread,
Apr 10, 2009, 12:07:02 PM4/10/09
to serv...@googlegroups.com
"exports" is *not* a keyword. Because of the bizarre behavior
associated with "this" in JS, several secure JS subsets (ADsafe,
Cajita, perhaps dojox secure?) ban it. Others (Jacaranda) severely
restrict its use.
--
Text by me above is hereby placed in the public domain

Cheers,
--MarkM

Ondrej Zara

unread,
Apr 10, 2009, 2:07:51 PM4/10/09
to serv...@googlegroups.com

Because of the bizarre behavior
associated with "this" in JS, several secure JS subsets (ADsafe,
Cajita, perhaps dojox secure?) ban it. Others (Jacaranda) severely
restrict its use.

Observation: a large portion of "this" abuses and misuses is just simply a result of poor knowledge of how "this" works in {java,ecma}script. Clearly, I am not stating that all people mentioned in the post above have low JS skills, but I have personally met a _huge_ amount of people confused with "this" just because they were not sufficiently familiarized with how it works.

In fact, I tend to agree with author of this thread. Having "exports" gives us sufficient "explicitness", but in fact introduces a new "reserved" word - and there are _plenty_ of problematic words ("super", "class", "char" and many more - see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Reserved_Words) in JS that cannot be used just because they are reserved.


Ondrej



 

Aristid Breitkreuz

unread,
Apr 10, 2009, 2:39:05 PM4/10/09
to serv...@googlegroups.com
Ondrej Zara schrieb:

> In fact, I tend to agree with author of this thread. Having "exports"
> gives us sufficient "explicitness", but in fact introduces a new
> "reserved" word - and there are _plenty_ of problematic words
> ("super", "class", "char" and many more - see
> https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Reserved_Words)
> in JS that cannot be used just because they are reserved.

exports will neither become reserved in any way, nor is it. It's just a
variable that is part of the securable modules API. (However, export
without s is a reserved word.)

Kris Kowal

unread,
Apr 10, 2009, 2:56:08 PM4/10/09
to serv...@googlegroups.com
On Fri, Apr 10, 2009 at 3:58 AM, Ryan Dahl <coldre...@gmail.com> wrote:
> All context layers in javascript use this; why should the top level
> context be different? Why introduce a new keyword. I'd rather view
> module files as constructor functions for objects.
>
> Also many browser scripts today can be immediately used with the
> module system if "this" is used instead of "exports":
> http://www.json.org/json2.js
> http://jqueryjs.googlecode.com/files/jquery-1.3.2.js

It's funny that you should mention jQuery. I wasn't aware that they
had finally shifted from using "window" directly to using "this". I
made this recommendation two years ago so that you could make this
argument today ;-) http://dev.jquery.com/ticket/1794.

Ihab and I also recommended that "this" be a synonym for "exports" to
support a migration phase where modern day scripts could also be used
as modules. The rationale is described in the section "Global/Salty
Script/Module" in "Importing Capabilities and Exporting a Module" in
our proposal to ECMA
http://docs.google.com/Doc?id=dfgxb7gk_34gpk37z9v&hl=en

However, "exports" is a better way to refer to explicitly denote
exported stuff for a couple reasons. For one, it would resemble our
intended syntax in a future ECMAScript standard, "export foo" being
sugar for "exports.foo". It also provides a name by which exports can
be referenced in /any/ nested scope; using "this" is a hazard in those
scope because it can be subverted by a third-party function caller.
Also, for the reasons Mark outlines, "this" is banned in most security
contexts, so to be interoperable, a module must not use "this" and
therefore must use the term "exports".

Also, the use of "exports" is not going to cause the same difficulties
as reserved keywords in the language. It is not a keyword, so you can
reassign it, declare variables by the same in inner scope, and any of
the other freedoms we as JavaScripters enjoy. A script may blissfully
use the term without knowledge that it's already in scope. Thankfully
"export" and "import" are reserved keywords, since we would like to
repurpose them in the future for "exports" and "require" sugar and
would not have such an opportunity otherwise.

While I am strongly in favor of providing a migration phase for modern
scripts, we as application programmers tend to do anything that works
and suits our fancy without regard or awareness of the tradeoffs, such
that if "this" is permitted to be used to refer to exports, it
certainly will be abused. For those that care, Chiron still permits
the use of "this" as a synonym for "exports" so that global scripts
can migrate for the time being, and I feel that addressing this issue
only in a client-side loader is sufficient and there need not be a
resolution by this group either requiring or disallowing the use of
"this" as a synonym of "exports".

Kris Kowal

Wes Garland

unread,
Apr 12, 2009, 12:36:48 AM4/12/09
to serv...@googlegroups.com
Kris;

Ihab and I also recommended that "this" be a synonym for "exports" to
support a migration phase where modern day scripts could also be used
as modules.  

This, however, precludes having modules with private functions and variables, AFAICS.

Consider the case of modules that look like this; if the outermost "this" is the module's scope, "myPrivateState" and "secretStuff" suddenly become module exports:

var myPrivateState = 3;
function secretStuff()
{
  ;
}

exports.exposedAPI = function() { secretStuff(myPrivateState) };

Wes

--
Wesley W. Garland
Director, Product Development
PageMail, Inc.
+1 613 542 2787 x 102

Ryan Dahl

unread,
Apr 12, 2009, 4:14:29 AM4/12/09
to serv...@googlegroups.com
> This, however, precludes having modules with private functions and
> variables, AFAICS.

If you just take the module file and wrap it in a constructor then it would

function require () {
return new function () { (module code) }
}

Ryan Dahl

unread,
Apr 12, 2009, 5:39:37 AM4/12/09
to serv...@googlegroups.com
One point that hasn't been brought up is the ease of moving submodule
out of a file. Consider this module.js:

exports.foo = function () {
return "foo";
}

exports.submodule = new function () {
function private () {
return "private";
}

this.hello = function () {
return "hello " + private();
};
};

Later the programmer decides that submodule should be in its own file.
The programmer creates a directory module/ and a file
module/submodule.js. Now he is faced with the task of renaming
"this.hello" to "exports.hello". Obviously this is not a huge problem
but it demonstrates that "this" is natural to export objects out of
the scope.

Wes Garland

unread,
Apr 12, 2009, 8:27:59 AM4/12/09
to serv...@googlegroups.com

1. Modules can't rewrite the require function; that breaks basic security.
2. Without rewriting require, sharing private variables among exported functions  starts to get a little ridiculous IMHO
3. "this" is certainly not the most natural way to export things, except when there is no other choice.  (Using a screwdriver to bang nails works; doesn't mean you shouldn't use a hammer when one is available)
4. You seem to be making the assumption that modules usually supply a single class, rather than a group of related things. I don't believe that is a reasonable assumption.
5. Have you taken a look at the discussions last month w.r.t. mutually-dependent module loading?
6. "Ease of porting" is a complete red herring.   "for (el in this) exports[el] = this[el];"
7. I am really getting sick and tired of talking about modules.  They were beaten to death in Jan, Feb and March. If we keep bike shedding like this, we're going to be sitting here next year doing the same damned thing.  Once again I am forced to wonder if people on this list are actually interested in CREATING a viable ssjs ecosystem, or opining about the prettiest one.  I would argue that having a working environment to try things in is way more important than talking about what might be, and changing hats every other week.

Ryan Dahl

unread,
Apr 12, 2009, 10:43:26 AM4/12/09
to serv...@googlegroups.com
> 1. Modules can't rewrite the require function; that breaks basic security.

I didn't explain myself well. I wasn't suggesting modules rewrite the
require function, rather I was suggesting that the data in a module
file be thought of the body of a constructor function. When viewed
this way, "this" is the natural a scope exporter.

> 4. You seem to be making the assumption that modules usually supply a single
> class, rather than a group of related things. I don't believe that is a
> reasonable assumption.

No..? Or maybe I miss understand you. For example:

var module = new function () {
function PrivateClass () { /* ... */ }
this.PublicClass1 = function () { /* ... */ };
this.PublicClass2 = function () { /* ... */ };
};

Ryan Dahl

unread,
Apr 12, 2009, 10:46:13 AM4/12/09
to serv...@googlegroups.com
> No..? Or maybe I miss understand you. For example:

misunderstand *facepalm*

Reply all
Reply to author
Forward
0 new messages