Dynamic Require API - Name

33 views
Skip to first unread message

Kris Kowal

unread,
Jan 26, 2011, 7:55:47 PM1/26/11
to comm...@googlegroups.com
On Wed, Jan 26, 2011 at 2:06 PM, khs4473 <khs...@gmail.com> wrote:
> - What to name the function?  The options that have been put forward
> are:

A.) module.provide (Wes Garland)
B.) module.load (KHS)
C.) require.ensure (Wes Garland)
D.) require.load
E.) define (James Burke, Kevin H Smith)

This issue is not orthogonal to "Dynamic Require API - Unification of
Require and Provide." Please comment on that thread.

Current show of hands. Please copy and update this block in responses.

A.) -1 Christoph Dorn
B.) -1 Christoph Dorn
C.)
D.)
E.) +1 Kris Kowal

Christoph Dorn on A and B: "module" is misleading here as the "module"
instance within a Modules/1.1 module has nothing to do with it.

Christoph Dorn on C: [require.ensure] asks "require" to load a module
+ require()-linked dependencies into the current sandbox and respects
module relative and top-level module IDs.

Kris Kowal

Mikeal Rogers

unread,
Jan 26, 2011, 7:57:26 PM1/26/11
to comm...@googlegroups.com
A.) -1 Christoph Dorn
B.) -1 Christoph Dorn
C.)
D.)
E.) +1 Kris Kowal +1 Mikeal Rogers

James Burke

unread,
Jan 26, 2011, 8:23:48 PM1/26/11
to comm...@googlegroups.com
On Wed, Jan 26, 2011 at 2:55 PM, Kris Kowal <kris....@cixar.com> wrote:
> On Wed, Jan 26, 2011 at 2:06 PM, khs4473 <khs...@gmail.com> wrote:
>> - What to name the function?  The options that have been put forward
>> are:
>
> A.) module.provide (Wes Garland)
> B.) module.load (KHS)
> C.) require.ensure (Wes Garland)
> D.) require.load
> E.) define (James Burke, Kevin H Smith)

F.) require([], function(){}) James Burke

Adding F instead of using E for the reasons I state in "Dynamic


Require API - Unification of Require and Provide."

F.) +1 James Burke

James

Kris Kowal

unread,
Jan 26, 2011, 8:52:42 PM1/26/11
to comm...@googlegroups.com

F has the disadvantage of advancing the responsibilities of an
existing function, meaning that new code in old implementations will
raise strange and confusing errors.

I'm for the use of "require" as a name-space since it can be carried
by fresh require properties in "Invocation Form C".

Let's re-factor the vote, between the two issues of namespace and name.

Namespace:
A.) None Kris Kowal +1, Mikael Rodgers +1, James Burke +1
B.) module Christoph Dorn -1, Kris Kowal -1
C.) require Kris Kowal +1

Name:
Z.) provide Kris Kowal -1
Y.) load Kris Kowal +1
X.) ensure Kris Kowal -1
W.) define Kris Kowal -1, James Burke -1, Christoph Dorn -1
V.) require James Burke +1 Kris Kowal -1

The votes agains "W" I carried over from "Unification of Require and Provide"

Kris Kowal

khs4473

unread,
Jan 26, 2011, 8:59:19 PM1/26/11
to CommonJS
namespace: module
reasoning: if we're going to push require as psuedo-syntax, then
require.load makes no more sense than import.load would in python. As
an educator, hanging anything off of require will weaken the psuedo-
syntax idea. Also, imagine a newbie asking, "how do I dynamically
load a module?". Answer: "module.load". Easy.

name: load
reasoning: principal of least suprise


On Jan 26, 8:52 pm, Kris Kowal <kris.ko...@cixar.com> wrote:
> On Wed, Jan 26, 2011 at 5:23 PM, James Burke <jrbu...@gmail.com> wrote:
> > On Wed, Jan 26, 2011 at 2:55 PM, Kris Kowal <kris.ko...@cixar.com> wrote:

Kris Kowal

unread,
Jan 26, 2011, 9:10:16 PM1/26/11
to comm...@googlegroups.com
On Wed, Jan 26, 2011 at 5:59 PM, khs4473 <khs...@gmail.com> wrote:
> namespace: module
> reasoning:  if we're going to push require as psuedo-syntax, then
> require.load makes no more sense than import.load would in python.  As
> an educator, hanging anything off of require will weaken the psuedo-
> syntax idea.  Also, imagine a newbie asking, "how do I dynamically
> load a module?".  Answer:  "module.load".  Easy.
> name: load
> reasoning: principal of least suprise

Namespace:


A.) None Kris Kowal +1, Mikael Rodgers +1, James Burke +1

B.) module Christoph Dorn -1, Kris Kowal -1, Kevin H Smith +1


C.) require Kris Kowal +1

Name:
Z.) provide Kris Kowal -1

Y.) load Kris Kowal +1, Kevin H Smith +1

Christoph Dorn

unread,
Jan 26, 2011, 9:32:06 PM1/26/11
to comm...@googlegroups.com

Going with require.load() as ID matching semantics and scoping are the
same as with require() and purpose is complementary.

(B) Seems like the wrong place for me

(A) Seems too ambiguous and does not imply ID matching equivalent to
require()


> Namespace:
> A.) None Kris Kowal +1, Mikael Rodgers +1, James Burke +1, Christoph Dorn -1
> B.) module Kris Kowal -1, Christoph Dorn -1, Kevin H Smith +1
> C.) require Kris Kowal +1, Christoph Dorn +1


>
> Name:
> Z.) provide Kris Kowal -1

> Y.) load Kris Kowal +1, Kevin H Smith +1, Christoph Dorn +1


> X.) ensure Kris Kowal -1
> W.) define Kris Kowal -1, James Burke -1, Christoph Dorn -1

> V.) require Kris Kowal -1, James Burke +1, Christoph Dorn -1

Christoph

Kris Kowal

unread,
Jan 26, 2011, 9:41:13 PM1/26/11
to comm...@googlegroups.com
On Wed, Jan 26, 2011 at 6:32 PM, Christoph Dorn
<christ...@christophdorn.com> wrote:
> Going with require.load() as ID matching semantics and scoping are the same
> as with require() and purpose is complementary.

Concurring. require and require.load are peas in a pod. I wouldn't
want to expand arguments or free-variables in this case.

Namespace:

A.) None
For: Mikeal Rodgers, James Burke
Against: Christoph Dorn
B.) module
For: Kevin H Smith
Against: Kris Kowal, Christoph Dorn
C.) require
For: Kris Kowal, Christoph Dorn

Name:

Z.) provide Kris Kowal -1

For:
Against: Kris Kowal
Y.) load
For: Kris Kowal, Kevin H Smith, Christoph Dorn
Against:
X.) ensure
For:
Against: Kris Kowal
W.) define
For:
Against: Kris Kowal, James Burke, Christoph Dorn
V.) require
For: James Burke
Against: Kris Kowal, Christoph Dorn

James Burke

unread,
Jan 26, 2011, 9:48:20 PM1/26/11
to comm...@googlegroups.com
On Wed, Jan 26, 2011 at 3:52 PM, Kris Kowal <kris....@cixar.com> wrote:
Require API - Unification of Require and Provide."
>>
>> F.) +1 James Burke
>
> F has the disadvantage of advancing the responsibilities of an
> existing function, meaning that new code in old implementations will
> raise strange and confusing errors.

I don't believe that require.x will fare much better. It will generate
an error, and likely lead to the developer having to look up or ask
about the error, and I believe that most code that would use this new
API will likely want to do it as part of a module API with a factory
function (define/module.declare), so a new baseline for what is
supported by require will be there. In other words, the developer will
likely hit the "no module factory API" error before hitting this
dynamic API.

James

Tom Robinson

unread,
Jan 27, 2011, 4:13:23 AM1/27/11
to comm...@googlegroups.com
+1: C, Y
-1: A, B, Z, W, V

provide and define make absolutely no sense.

On Jan 26, 2011, at 6:41 PM, Kris Kowal wrote:

> On Wed, Jan 26, 2011 at 6:32 PM, Christoph Dorn
> <christ...@christophdorn.com> wrote:
>> Going with require.load() as ID matching semantics and scoping are the same
>> as with require() and purpose is complementary.
>
> Concurring. require and require.load are peas in a pod. I wouldn't
> want to expand arguments or free-variables in this case.
>
Namespace:

A.) None
For: Mikeal Rodgers, James Burke

Against: Christoph Dorn, Tom Robinson


B.) module
For: Kevin H Smith

Against: Kris Kowal, Christoph Dorn, Tom Robinson
C.) require
For: Kris Kowal, Christoph Dorn, Tom Robinson

Name:

Z.) provide
For:
Against: Kris Kowal, Tom Robinson
Y.) load
For: Kris Kowal, Kevin H Smith, Christoph Dorn, Tom Robinson


Against:
X.) ensure
For:
Against: Kris Kowal
W.) define
For:

Against: Kris Kowal, James Burke, Christoph Dorn, Tom Robinson


V.) require
For: James Burke

Against: Kris Kowal, Christoph Dorn, Tom Robinson

Hannes Wallnoefer

unread,
Jan 27, 2011, 6:00:34 AM1/27/11
to comm...@googlegroups.com
+1 for "load", -1 for piggybacking semantics on existing functions. I
never liked the dual meaning of require() in RequireJS, in fact I
proposed to add a "load" function on this list back in November
<https://gist.github.com/661185>.

I'm a bit torn on the namespace issue. I'd love to have none but
voting "require" for the obvious pragmatical reason that it's there
already.

Namespace:

A.) None
For: Mikeal Rodgers, James Burke
Against: Christoph Dorn, Tom Robinson
B.) module
For: Kevin H Smith
Against: Kris Kowal, Christoph Dorn, Tom Robinson
C.) require

For: Kris Kowal, Christoph Dorn, Tom Robinson, Hannes Wallnoefer

Name:

Z.) provide
For:
Against: Kris Kowal, Tom Robinson
Y.) load

For: Kris Kowal, Kevin H Smith, Christoph Dorn, Tom Robinson, Hannes Wallnoefer
Against:
X.) ensure
For:
Against: Kris Kowal, Hannes Wallnoefer
W.) define
For:
Against: Kris Kowal, James Burke, Christoph Dorn, Tom Robinson,
Hannes Wallnoefer


V.) require
For: James Burke

Against: Kris Kowal, Christoph Dorn, Tom Robinson, Hannes Wallnoefer

Irakli Gozalishvili

unread,
Jan 27, 2011, 9:03:26 AM1/27/11
to comm...@googlegroups.com
C +, W +

Regards
--
Irakli Gozalishvili
Web: http://www.jeditoolkit.com/
Address: 29 Rue Saint-Georges, 75009 Paris, France



--
You received this message because you are subscribed to the Google Groups "CommonJS" group.
To post to this group, send email to comm...@googlegroups.com.
To unsubscribe from this group, send email to commonjs+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/commonjs?hl=en.


khs4473

unread,
Jan 27, 2011, 11:25:31 AM1/27/11
to CommonJS
None of the options for namespace are optimal:

None: this would mean adding another free variable, which will impact
any wrappings/transport spec. Plus each free variable adds a little
bit of "noise".

require: I want to teach CJS require as a psuedo-keyword (with the
addition of a LOAD api, that's what it effectively becomes). Hanging
anything off of it (other than what's already hung off it) makes it
look less like a keyword and more like an API. That's confusing.

module: The subject and verb don't match. If "load" is the verb, the
subject is really "module loader" or "module context" or something
like that.

That said, I prefer "module" because I think the "require-as-keyword"
thing is important. But I might be willing to bend on this.

khs


On Jan 27, 9:03 am, Irakli Gozalishvili <rfo...@gmail.com> wrote:
> C +, W +
>
> Regards
> --
> Irakli Gozalishvili
> Web:http://www.jeditoolkit.com/
> Address: 29 Rue Saint-Georges, 75009 Paris, France <http://goo.gl/maps/3CHu>
> > commonjs+u...@googlegroups.com<commonjs%2Bunsubscribe@googlegroups.c om>
> > .

Kris Kowal

unread,
Jan 27, 2011, 12:14:33 PM1/27/11
to comm...@googlegroups.com
Irakli, is your vote based on the notion that this syntax will also be
used as a wrapping for module declaration in script-injected modules?
It looks like consensus is in the other direction, and that this API
would only be used for lazy loading and for computed dependencies.


A.) None
For: Mikeal Rodgers, James Burke
Against: Christoph Dorn, Tom Robinson
B.) module
For: Kevin H Smith
Against: Kris Kowal, Christoph Dorn, Tom Robinson
C.) require

For: Kris Kowal, Christoph Dorn, Tom Robinson, Hannes Wallnoefer,
Irakli Gozalishvili

Name:

Z.) provide
For:
Against: Kris Kowal, Tom Robinson
Y.) load
For: Kris Kowal, Kevin H Smith, Christoph Dorn, Tom Robinson, Hannes Wallnoefer
Against:
X.) ensure
For:
Against: Kris Kowal, Hannes Wallnoefer
W.) define

For: Irakli Gozalishvili

Wes Garland

unread,
Jan 27, 2011, 1:19:29 PM1/27/11
to comm...@googlegroups.com
On Thu, Jan 27, 2011 at 11:25 AM, khs4473 <khs...@gmail.com> wrote:
None of the options for namespace are optimal:

None of the given options matches the semantics I have previously proposed, via Modules/2.0-draft7, either.

To re-iterate my view, I believe we should treat both require and module as namespacing objects:
  • The module namespace deals with the local module and the module system in general.
  • The require namespace deals with the hidden module memo -- so, properties of require affect what require() does.

This is already consistent with module.id and require.path -- require.path changes the way the hidden module memo is exported. require() is how we access the hidden module memo.

I also think that require.main should be deprecated, and that module.main should be added. Module.main would be a pointer to the main module's exports. It addresses the the self-identification use-case that require.main was added for, without publishing the main module's module object for all to see.

It should also be pointed out that require may be passed from one module to for authority hand-off purposes.  I expect this to become a more interesting use-case as sandboxing technology evolves.  I would not want to hang anything off require which does not directly have anything to do with require(), because there is no way in EcmaScript to pass around just the function-bits of a function-object.

Wes

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

Christoph Dorn

unread,
Jan 27, 2011, 1:30:54 PM1/27/11
to comm...@googlegroups.com

On 11-01-27 10:19 AM, Wes Garland wrote:
> It should also be pointed out that require may be passed from one module
> to for authority hand-off purposes. I expect this to become a more
> interesting use-case as sandboxing technology evolves. I would not want
> to hang anything off require which does not directly have anything to do
> with require(), because there is no way in EcmaScript to pass around
> just the function-bits of a function-object.

That is why I think require.load() is ideal as it must follow the same
ID logic as require() with the exception that the modules may not be
available already and may need to be loaded (and it's async obviously vs
sync require()).

I would be open to require.async(). It makes less of a statement about
*loading* and emphasizes the aspect of a module not being immediately
available as opposed to the sync require().

Adding option (U).

A.) None
For: Mikeal Rodgers, James Burke
Against: Christoph Dorn, Tom Robinson
B.) module
For: Kevin H Smith
Against: Kris Kowal, Christoph Dorn, Tom Robinson
C.) require

For: Kris Kowal, Christoph Dorn, Tom Robinson, Hannes Wallnoefer,
Irakli Gozalishvili

Name:

Z.) provide
For:
Against: Kris Kowal, Tom Robinson
Y.) load
For: Kris Kowal, Kevin H Smith, Christoph Dorn, Tom Robinson, Hannes
Wallnoefer
Against:
X.) ensure
For:
Against: Kris Kowal, Hannes Wallnoefer
W.) define

For: Irakli Gozalishvili


Against: Kris Kowal, James Burke, Christoph Dorn, Tom Robinson,
Hannes Wallnoefer
V.) require
For: James Burke
Against: Kris Kowal, Christoph Dorn, Tom Robinson, Hannes Wallnoefer

U.) async
For: Christoph Dorn

Tom Robinson

unread,
Jan 27, 2011, 1:37:22 PM1/27/11
to comm...@googlegroups.com
+1 U, my other votes remain.

Name:

For: Christoph Dorn, Tom Robinson

Florian Traverse

unread,
Jan 27, 2011, 1:50:02 PM1/27/11
to comm...@googlegroups.com
Well, you've forgotten mine, summarizable as

module
.using("module/name1").as("module1")
.using("module/name2)
.define(function(require, exports, module){
 var foo = require("module1"),
       bar= require("module/name2");

...

})

So I guess mine should be in the module "namespace" (so +1 for B) and a new "name" :

T) using/as/define

2011/1/27 Tom Robinson <tlrob...@gmail.com>
--
You received this message because you are subscribed to the Google Groups "CommonJS" group.
To post to this group, send email to comm...@googlegroups.com.
To unsubscribe from this group, send email to commonjs+u...@googlegroups.com.

Wes Garland

unread,
Jan 27, 2011, 1:50:04 PM1/27/11
to comm...@googlegroups.com
On Thu, Jan 27, 2011 at 1:30 PM, Christoph Dorn <christ...@christophdorn.com> wrote:
That is why I think require.load() is ideal as it must follow the same ID logic as require() with the exception that the modules may not be available already and may need to be loaded (and it's async obviously vs sync require()).

I'll give you the point that you've got a valid argument here, however I disagree with your conclusions.  The disagreement is centered around my belief that require should only deal with the hidden module memo.  If you passed a require() into a sandbox that has a load method, you pass the sandbox the ability to use the method -- rather than just the ability to use the exports memo.

I have proposed in the past that module loading be handled in the module namespace, with calls into the require namespace to write into the module memo... So, in my vision, require could be as simple as something like the following untested code:

var hiddenMemo = {};
var pendingFactories = {};

function require(moduleIdentifier) {
  var moduleId = canonicalize(moduleIdentifier);
   if (!hiddenMemo[moduleId] && !pendingFactories[moduleId])
     throw new Error('oops');

   if (pendingMemo[moduleId])  {
      pendingFactories[moduleId](requireFactory(), hiddenMemo[moduleId], new Module(moduleId));
      delete pendingFactorues[moduleId];
   }
   return hiddenMemo[moduleId];
}

require.memoize = function(moduleIdentifier, moduleFactory) {
  var moduleId = canonicalize(moduleIdentifier);
  hiddenMemo[moduleId] = {};

  pendingFactories[moduleId] = moduleFactory;  
}

...i.e., I want to see require() completely decoupled from the mechanics of loading modules.

As soon as we do that, we suddenly have another advantage: by replacing or adjusting the module namespace, you can implement new module, package, and transport formats onto an arbitrary CommonJS environment.  This means that the rate of CommonJS growth can increase, and it can grow by trial/error tests, market-uptake decisions, etc -- rather than endless threads of bikeshedding votes.
 
I would be open to require.async(). It makes less of a statement about *loading* and emphasizes the aspect of a module not being immediately available as opposed to the sync require().

Why does require have to be either sync or async?   Will async require() work in sync-mode environments, or should we split the module universe in two?

Wes

Patrick Mueller

unread,
Jan 27, 2011, 1:58:40 PM1/27/11
to comm...@googlegroups.com
On Thu, Jan 27, 2011 at 11:25, khs4473 <khs...@gmail.com> wrote:
None of the options for namespace are optimal:

None: this would mean adding another free variable, which will impact
any wrappings/transport spec.  Plus each free variable adds a little
bit of "noise".

So then here's another option.  Package this glorp up as functions in a new "system" module.  It would need a special character in the name to keep from clobbering any user-specified modules.  In this case, call it "!loader" or ":loader".  CommonJS impls would then implement this module as a built-in.  Using it would then be as:

    var loader = require(":loader")
    loader.loadAsync(whatever)

I mean, modules are great, right?  Let's use them.  :-)

I'm currently on tack to do something similar with modjewel, only the "system" module in this case is called "modjewel".  Load my library, you get require() and one loadable module (named "modjewel") for free.  

--
Patrick Mueller
http://muellerware.org

Kris Kowal

unread,
Jan 27, 2011, 2:03:25 PM1/27/11
to comm...@googlegroups.com
On Thu, Jan 27, 2011 at 10:58 AM, Patrick Mueller <pmu...@gmail.com> wrote:
> So then here's another option.  Package this glorp up as functions in a new
> "system" module.  It would need a special character in the name to keep from
> clobbering any user-specified modules.  In this case, call it "!loader" or
> ":loader".  CommonJS impls would then implement this module as a built-in.
>  Using it would then be as:
>     var loader = require(":loader")
>     loader.loadAsync(whatever)
> I mean, modules are great, right?  Let's use them.  :-)
> I'm currently on tack to do something similar with modjewel, only the
> "system" module in this case is called "modjewel".  Load my library, you get
> require() and one loadable module (named "modjewel") for free.

Great to hear from you again; you've been missed. This approach is
certainly fine, especially if we don't find consensus elsewhere.

Kris Kowal

Christoph Dorn

unread,
Jan 27, 2011, 2:09:12 PM1/27/11
to comm...@googlegroups.com
On 11-01-27 10:50 AM, Wes Garland wrote:
> On Thu, Jan 27, 2011 at 1:30 PM, Christoph Dorn
> <christ...@christophdorn.com <mailto:christ...@christophdorn.com>>

> wrote:
>
> That is why I think require.load() is ideal as it must follow the
> same ID logic as require() with the exception that the modules may
> not be available already and may need to be loaded (and it's async
> obviously vs sync require()).
>
> I'll give you the point that you've got a valid argument here, however I
> disagree with your conclusions. The disagreement is centered around my
> belief that require should only deal with the hidden module memo. If

Right.

> you passed a require() into a sandbox that has a load method, you pass
> the sandbox the ability to use the method -- rather than just the
> ability to use the exports memo.

Right. The point is to pass in the ability to use the load method.


> I have proposed in the past that module loading be handled in the module
> namespace, with calls into the require namespace to write into the
> module memo...

I see the module namespace reserved for:

1) Keeping info about the current module (module.is, module.path)
2) Declaring a module (module.declare)

When loading modules with require.load/async() you are loading them into
the *sandbox* after which point they are available to all modules in the
sandbox.

If you need to keep the loaded modules separate you should create a new
sandbox and load the modules into that.

As for authority to load modules into the sandbox. The sandbox config
can veto what the loader can load and this works even when require is
passed off into another sandbox (the original sandbox would still have
control which is the intended behavior).

> ...i.e., I want to see require() completely decoupled from the mechanics
> of loading modules.
>
> As soon as we do that, we suddenly have another advantage: by replacing
> or adjusting the module namespace, you can implement new module,
> package, and transport formats onto an arbitrary CommonJS environment.
> This means that the rate of CommonJS growth can increase, and it can
> grow by trial/error tests, market-uptake decisions, etc -- rather than
> endless threads of bikeshedding votes.

I don't see how this would not be possible with require.load/async().


> I would be open to require.async(). It makes less of a statement
> about *loading* and emphasizes the aspect of a module not being
> immediately available as opposed to the sync require().
>
> Why does require have to be either sync or async? Will async require()
> work in sync-mode environments, or should we split the module universe
> in two?

require() assumes modules are available
require.load/async() assumes one or more modules still need to be loaded
or somehow made available by the loader in a fashion that will not
return right away but we need to know when ready.

Christoph


Wes Garland

unread,
Jan 27, 2011, 4:15:49 PM1/27/11
to comm...@googlegroups.com
On Thu, Jan 27, 2011 at 2:09 PM, Christoph Dorn <christ...@christophdorn.com> wrote:
As for authority to load modules into the sandbox. The sandbox config can veto what the loader can load and this works even when require is passed off into another sandbox (the original sandbox would still have control which is the intended behavior).

But the sandbox config cannot veto *who* can load.  So, if we decide we want to pass around the authority to ask for a bunch of different modules' exports, we pass around require().  If we put .load on require(), that also gives the sandbox the ability load new modules with the same authority as the require-owner.

This *is* a very small distinction, though.

This means that the rate of CommonJS growth can increase, and it can
grow by trial/error tests, market-uptake decisions, etc -- rather than
endless threads of bikeshedding votes.

I don't see how this would not be possible with require.load/async().


When the only primitive you have to write into the module memo is require.load(), it means you cannot extend the functionality of a module system -- you have to re-implement it from scratch.

For example, if you want to write a module system which loads modules from a fancy database over web sockets in an environment like modules/2.0-draft7, you write code to fetch modules from the database (by overriding properties on the module prototype).  This new code then tells the module system about the modules it has fetched with a call to require.memoize().

You cannot implement that with require.load() without modifying the underlying environment. This obviously is not portable from platform to platform. My vision allows a single author to invent something new in the module space, and deploy it on every platform without change.


Why does require have to be either sync or async?   Will async require()
work in sync-mode environments, or should we split the module universe
in two?


require() assumes modules are available
require.load/async() assumes one or more modules still need to be loaded or somehow made available by the loader in a fashion that will not return right away but we need to know when ready.


Is anybody prepared to discuss or specify how to implement require.async() on platforms which do not have an intrinsic event loop?

(I have done so with module.provide but this part of the discussion has been approximately ignored AFAICT)

Wes

Christoph Dorn

unread,
Jan 28, 2011, 1:43:43 PM1/28/11
to comm...@googlegroups.com
On 11-01-27 1:15 PM, Wes Garland wrote:
> On Thu, Jan 27, 2011 at 2:09 PM, Christoph Dorn
> <christ...@christophdorn.com <mailto:christ...@christophdorn.com>>

> wrote:
>
> As for authority to load modules into the sandbox. The sandbox
> config can veto what the loader can load and this works even when
> require is passed off into another sandbox (the original sandbox
> would still have control which is the intended behavior).
>
> But the sandbox config cannot veto *who* can load. So, if we decide we
> want to pass around the authority to ask for a bunch of different
> modules' exports, we pass around require(). If we put .load on
> require(), that also gives the sandbox the ability load new modules with
> the same authority as the require-owner.
>
> This *is* a very small distinction, though.

But a very important one at this foundational level. I can see uses for
this in my code today. In revisiting my thinking about the namespace it
actually makes a lot of sense to hang it off module.

It states that a module has an optional dependency on another module vs
a required dependency and this optional dependency can be traced back to
the module at any time just like static dependencies can.


> require() assumes modules are available
> require.load/async() assumes one or more modules still need to be
> loaded or somehow made available by the loader in a fashion that
> will not return right away but we need to know when ready.
>
> Is anybody prepared to discuss or specify how to implement
> require.async() on platforms which do not have an intrinsic event loop?
>
> (I have done so with module.provide but this part of the discussion has
> been approximately ignored AFAICT)

I am not prepared as I do not understand the implications and quite
frankly lack the vocabulary and experience to participate effectively.
That is why I am glad you and others who can reason at this level are on
board.

I work at a high level of abstraction most of the time and coming down
to this level of specification (including the ins and outs of
Modules/2.0) I find very taxing. That is the reason why I have not
looked at your Modules/2.0 draft in detail. I find it overwhelming in
terminology and scope. I would however like to understand the
implications and opportunities it presents to users of implementations
that follow the spec and I do believe my feedback is valuable in this area.

I am a visual thinker and it helps me a lot to see relationships in a
diagram to understand something as comprehensive as the CommonJS system
provides. I am going to take Sander's suggestion and work on a diagram
to provide an overview of Modules/2.0 and how it fits into the big
CommonJS picture.

I hope we can use such a diagram as an aid to provide context to
discussions and introduce new users to writing programs with CommonJS.

Christoph

johnjbarton

unread,
Feb 1, 2011, 11:33:03 AM2/1/11
to CommonJS


On Jan 26, 4:55 pm, Kris Kowal <kris.ko...@cixar.com> wrote:
> On Wed, Jan 26, 2011 at 2:06 PM, khs4473 <khs4...@gmail.com> wrote:
> > - What to name the function?  The options that have been put forward
> > are:
>
> A.) module.provide (Wes Garland)
> B.) module.load (KHS)
> C.) require.ensure (Wes Garland)
> D.) require.load
> E.) define (James Burke, Kevin H Smith)

I thought (for once ;-) I did not have an opinion on the name. Now I
realize I do.

I think we need to define and thus name three (not two things):
1) how to configure the loader, (base)
2) how to start up the dependency loading, (root) aka LOAD
3) how to recurse on dependency loading, (branches) aka define()/
module.declare().
We've discussed 2 and 3 quite a bit. But we missed #1. (Separately
I've argued that 2==3, but here I will treat them differently and I
can even give an argument for why they ought to be separate now).

I think that mostly we have been assuming that configuration is out of
scope. Let's reconsider. Certainly web browser extensions, server app
frameworks, and web app frameworks will need multiple loaders because
each loader controls security. Even less ambitious projects may need
multiple loaders in the coming era of cross-site web apps. The analogy
is iframes: you can create a page without iframes, but some sites are
much better with them.

(Just to make this less scary, it's completely reasonable for part of
the configuration API to be environment dependent and not spec'ed.).

Let's just try this out to see what happens. The essential ingredient
is allow creation of a loader. (I'm biasing the name already, but I
don't want to call it "It" ;-). While I hate 'new', I'll save that
battle for another day:

var loader = new ModuleLoader(/* env dep args*/);
Maybe you prefer:
var modules = new Modules(/* env dep args*/);
but you probably won't care for:
var requirement = new Requirement(/* env dep args*/);
or
var require = new Require(/* env dep args*/);

I guess now you can see where this is headed: the namespace for the
LOAD function is the object returned by the configuration call:

loader.load(/* see args discussion */);
modules.load(/* see args discussion */);
requirement.load(/* see args discussion */);
require.load(/* see args discussion */);

While superficially these look like alternatives discussed on this
thread, these are not functions of a global namespace but functions on
an instance of a class in the global namespace. Therefore the spec
needs to give the name of the class and the instance method, but not
the instance.

The final element is the module-defining syntax (define/
module.declare...). In principle we could use anything: we don't need
to couple the decision about the module-defining syntax to the above
discussion. But using the same reasoning others have applied about
minimizing name pollution and increasing coherence, the logical choice
for the namespace would the module loader class:

ModuleLoader.declare(/* see args discussion */);
Modules.declare(/* see args discussion */);
Requirement.declare(/* see args discussion */);
Require.declare(/* see args discussion */);

Of course the method name is still up for discussion. Conceptually the
namespace role is not different here from the require.<xx> or
module.<xx> choices, it's just that the name of the namespace now
logically moves to our choice for the loader class.

I'm sure some will say the extra complication of the class is
unnecessary, so I'll just throw out one more idea: we could define the
default loader instance name and recover simplicity for a subset of
users.

jjb

Wes Garland

unread,
Feb 1, 2011, 12:05:07 PM2/1/11
to comm...@googlegroups.com
John:

If I understand your proposal, this is largely similar to what Modules/2.0-draft8 tries to do by formally defining locations on the module object's constructor which can be overridden via monkey-patching "plugins" --

Overriding .load allows you to have an alternate module loading mechanism.  The same plug-ins I wrote with BravoJS illustrate this by re-implementing the loader with jQuery.ajax and lazyLoad.js (two different examples).

Overriding .declare allows you to adjust the module declaration format, such as allowing an alternate way to declare dependencies (see the BravoJS example I posted for Florian's syntax), load Modules/1.1.1 modules into a /2.0 environment (see the BravoJS jQuery plug-in), and potentially, packages and mappings (I haven't written any full working examples yet, but I believe they are also feasible).

.load and .declare are inextricably tied to one another because .load needs to feed the module identifier in a secure way somehow to .declare.   .declare also needs hooks into require(), this is what the require.memoize method is used for.

.provide is the formal interface in /2.0d8 to load multiple modules.   In some circumstances, overriding .provide might be necessary if there are limitations in the implementation of the supplied .load -- the circumstance where I have seen this is if the loader is incapable of loading modules in parallel (i.e. where multiple requests may complete out-of-order) and the environment's native .provide allows this.  Supplying a serializing .provide along with your custom loader is trivial.

The loader can be override globally (what I have been playing with, mostly) and locally; depending on if you override the own properties of module, or the properties on the constructor's prototype.  I am unsure if there is concrete benefit to local overrides outside of the extra-module environment, but allowing it does not seem to cause either implementation nor specification problems.

Overriding is done in /2.0d8 by accessing modules.constructor.prototype -- this means that we do not need to introduce any new symbols in the global scope  (module is mandatory in Modules/1.1).

So far, my experiments all involve loading extra code into the extra-module environment, either via HTML scripts tags or a GPSEE facility designed for this on the server-side ("preload file"), however, I foresee no difficulties with loading the plug-ins as modules, either.

Wes

--
You received this message because you are subscribed to the Google Groups "CommonJS" group.
To post to this group, send email to comm...@googlegroups.com.
To unsubscribe from this group, send email to commonjs+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/commonjs?hl=en.

johnjbarton

unread,
Feb 1, 2011, 12:35:18 PM2/1/11
to CommonJS


On Feb 1, 9:05 am, Wes Garland <w...@page.ca> wrote:
> John:
>
> If I understand your proposal, this is largely similar to what
> Modules/2.0-draft8 tries to do by formally defining locations on the module
> object's constructor which can be overridden via monkey-patching "plugins"
> --
>
> Overriding .load allows you to have an alternate module loading mechanism.

I guess that your proposal is "up one level" from what I described.

In my terms you are allowing ModuleLoader subclasses with overriding
methods. It's fine but not what I was describing. I was talking about
a single ModuleLoader class with a single -- parameterized -- module
loading mechanism. Each instance would have the same module loading
mechanism but different parameters.

Use cases include:
jetpack and firebug: same loading mechanism, different default
scopes.
firebug extn and firebug console implementation: same loading
mechanism, different security origins
cross-site web apps: same loading mechanism, different security
origins,
server servlets: same loading mechanism, different security
origins,
greasemonkey user scripts: same loading mechanism, different
default scopes.

jjb

Christoph Dorn

unread,
Feb 2, 2011, 7:15:22 PM2/2/11
to comm...@googlegroups.com
On 11-02-01 9:05 AM, Wes Garland wrote:
> Overriding .declare allows you to adjust the module declaration format,
> such as allowing an alternate way to declare dependencies (see the
> BravoJS example I posted for Florian's syntax), load Modules/1.1.1
> modules into a /2.0 environment (see the BravoJS jQuery plug-in), and
> potentially, packages and mappings (I haven't written any full working
> examples yet, but I believe they are also feasible).

I am going to try and add package mappings support to BravoJS. Any
pointers before I get started?

Should it be a plugin or should I add support to the loader itself?

Christoph

Christoph Dorn

unread,
Feb 3, 2011, 8:47:43 PM2/3/11
to comm...@googlegroups.com

FYI; Got it all working for relative 'location' mappings. Had to make a
number of changes/additions to the loader. Some more changes tomorrow
and we can discuss to fine-tune the patch and spec.

Christoph

Wes Garland

unread,
Feb 4, 2011, 6:47:31 PM2/4/11
to comm...@googlegroups.com
Excellent!  I can't wait to see what you've done, and whether we need to adjust Modules/2.0 to allow this cleanly  (or if we just have BravoJS implementation gotchas).

Sorry I haven't been any help this week -- I have been off sick.

If you haven't seen it yet, you should look at the plug-in I wrote to demonstrate Florian Tavares' alternate module dependency declaration syntax.   It's a shim that works by modifying the dependency array to add labelled dependencies before feeding to the 'real' module.declare.

Wes



Christoph

--
You received this message because you are subscribed to the Google Groups "CommonJS" group.
To post to this group, send email to comm...@googlegroups.com.
To unsubscribe from this group, send email to commonjs+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/commonjs?hl=en.

Reply all
Reply to author
Forward
0 new messages