Re: Questions about Harmony Modules

2011-04-06 Thread David Herman
 Why I was asking -- because I saw it in your talk on ES.next, where you used 
 exactly this approach, i.e. module Foo = http://modules.com/foo.js; -- 
 without any `require`. That's it.

No problem, I didn't mean to chastise. Just trying to keep focussed.

 (should I fix my following presentation also? I used the same as in yours)

Sure. Surface syntax isn't set in stone, but we aren't likely to go back to 
just the string literal, since it looks too much like the module is being 
assigned a string value. The current syntax is:

module Foo = require http://modules.com/foo.js;;
import Foo.bar;

where you can also parenthesize the whole require expression:

module Foo = (require http://modules.com/foo.js;);
import Foo.bar;

or more simply:

import (require http://modules.com/foo.js;).bar;

Dave

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Questions about Harmony Modules

2011-04-06 Thread James Burke
On Wed, Apr 6, 2011 at 8:25 AM, David Herman dher...@mozilla.com wrote:
 Sure. Surface syntax isn't set in stone, but we aren't likely to go back to 
 just the string literal, since it looks too much like the module is being 
 assigned a string value.

I know you do not want to get into bikeshedding at this point, and I
will not follow this up any more unless you explicitly ask me, but I
strongly encourage just using the string value, sans require. It is
much more concise, and OK given that modules are special (compile-time
processing, special injection via import).

If string IDs are allowed for inline module declarations to allow
optimization bundling:

module some/thing {}

that would help feed the consistency when seeing: module M = some/thing.

James
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Questions about Harmony Modules

2011-04-04 Thread David Herman
 Regarding, import M.* via destructuring, it's also arguable whether we 
 don't need it since it looks like a with.

I don't see any sense in which it looks like a |with|. It's both syntactically 
and semantically different. Syntactically, because it's a global (or 
module-global) declaration rather than a local statement form, and 
semantically, because it imports all the bindings at compile-time.

 then (theoretically!) why not to have `let {} = Mod`

because that is ambiguous with existing destructuring syntax

 (or any other syntax, e.g. let * = Mod)

because that would be dynamically evaluating the module expression and 
dynamically importing all the bindings, and hence tantamount to |with|.

 But, IMO it just looks more complicated than import Mod.*.

I agree. Part of the point of import is to create a distinct syntactic context 
for module expressions. Mixing this in with ordinary expressions and 
destructuring confuses the issue.


 (We've talked a little bit about generalizing the `require' form to be an 
 expression operator that does a static module load, but I'm not sure whether 
 it hangs together.)
 
 This is the question of allowing expression which we talked in the Narcissus 
 list

No, it's a different issue. You were talking about export declarations. Here I 
was talking about allowing you to statically load a module in any expression.

 (https://mail.mozilla.org/pipermail/narcissus/2011-March/43.html ; btw, 
 is it worth to put the discussing on duplications on this list?).

Not really. It's a pretty specific detail and we'll sort it out. It's not worth 
spending time discussing.

 Though the other question is: why do we need `require` at all?

Purely for syntactic/practical reasons. Let's not bikeshed.

Dave

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Questions about Harmony Modules

2011-04-04 Thread Dmitry A. Soshnikov

On 04.04.2011 18:40, David Herman wrote:



Though the other question is: why do we need `require` at all?

Purely for syntactic/practical reasons. Let's not bikeshed.



Why I was asking -- because I saw it in your talk on ES.next, where you 
used exactly this approach, i.e. module Foo = 
http://modules.com/foo.js; -- without any `require`. That's it. (should 
I fix my following presentation also? I used the same as in yours)


Agreed on rest points.

Dmitry.
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Questions about Harmony Modules

2011-04-03 Thread Dmitry A. Soshnikov

On 03.04.2011 3:33, David Herman wrote:

Hi James,


1) Files as modules do not need module wrapper

Just to confirm, if a JS file contains only a module definition, the
module X{} wrapper is not needed?

That's correct.

2) Set module export value


Is it possible to support setting the value of the module to be a
function or some other value?

Currently, there's nothing like this in the proposal, but I remember you blogged about 
this before. Harmony modules are static entities, and setting their value 
dynamically would clash with the design goals of static importing and exporting.

That said, we could consider adding functionality to make a module callable, to 
address the use case you describe. Thanks for bringing this up.


3) Are module and import needed inside a module?


There are two questions here:

3a) Is module needed inside a module?

Yes. A module declaration declares a binding to a static module. A let/var 
declaration declares a binding to a dynamic value. You only get compile-time 
linking and scoping with static modules.

3b) Is import needed inside a module?

I think the answer here is technically no. You're right that you could 
generally use let/var and destructuring, except for the import M.* case. If we 
allowed you to destructure a runtime expression and dynamically bind all its 
variables, we would be re-introducing `with' into Harmony, which we will never, 
ever, ever do. :)


Yes, since technically it's possible to get a value of an exported 
binding directly via:


let foo = Mod.foo;

then it should be possible to use destructuring to get references for 
several bindings.


However, as noticed, such imported via assignment bindings aren't 
static. I.e. it's possible e.g to assign to them in contrast if the 
binding is imported. Here I showed this difference: 
https://gist.github.com/885534 While this example is shown on prototyped 
modules in Narcissus, actually technically for real modules 
implementation there can be overloaded operator of assignment which 
calls `defineProperty` instead to make the binding the same as it was 
imported.


Regarding, import M.* via destructuring, it's also arguable whether we 
don't need it since it looks like a with. Besides, if we can import 
all via partial destructuring, i.e.:


module Mod {
export foo var = 10;
export bar var = 20;
}

let {foo, bar} = Mod;

then (theoretically!) why not to have `let {} = Mod` (or any other 
syntax, e.g. let * = Mod). But, IMO it just looks more complicated than 
import Mod.*. So I would disallow `let {} = Mod` not because of `with`, 
but because of the oddness of the construction which sounds as destruct 
the module Mod into the empty object.



The other difference -- at least in the current state of the proposal -- is 
that you can't use a `require' form in an ordinary expression, only in the RHS 
of an import/module declaration. This doesn't show up in the Geometry example 
you cited, but if you wanted to import from an external module using `let', you 
would have to use the callback API:

 ModuleLoader.load(geometry.js, function(Geometry) {
 let { draw } = Geometry;
 ...
 });

(We've talked a little bit about generalizing the `require' form to be an 
expression operator that does a static module load, but I'm not sure whether it 
hangs together.)



This is the question of allowing expression which we talked in the 
Narcissus list 
(https://mail.mozilla.org/pipermail/narcissus/2011-March/43.html ; 
btw, is it worth to put the discussing on duplications on this list?).


Though the other question is: why do we need `require` at all? Why not just:

// loading from the local file system

module $ = ./selector.js;

// loading from Net

module Widgets = http://mysite.com/widgets.cs;;

Though, I see the only case with destructuring (assuming that the module 
isn't on local system):


let {foo, bar} = require http://mysite.com/widgets.cs;

But since you notice that `require` won't be allowed in such expression, 
I don't see why it's needed at all.


Besides, I can imagine something like this:

import widgets/panel

which loads file panel.js from the widgets directory and either 
creates the module binding name as `Panel` (i.e corresponding to the 
file name), or imports all bindings from the module. Another variant:


import widgets/panel {foo, myBar: bar}

or

import {foo, myBar: bar} from widgets/panel

Dmitry.


The end goal is trying limit the number of new special things in the
language the developer needs to learn for modules. Ideally it would
be: use 'module' to declare an inline module, then use require('')
inside it to get handles on other modules, and use var/let and
destructuring as you normally would.

For many cases, I think that's fine. But .* is an important convenience for 
scripting. Also, FWIW, import is already reserved and has symmetry with export, 
so it seems like a wasted opportunity to 

Re: Questions about Harmony Modules

2011-04-03 Thread James Burke
On Sat, Apr 2, 2011 at 4:33 PM, David Herman dher...@mozilla.com wrote:
 2) Set module export value
 
 That said, we could consider adding functionality to make a module callable, 
 to address the use case you describe. Thanks for bringing this up.

Allowing a callable module would go a long way towards bridging the
gap with settings exports as that is the primary use of that
feature, although it has been useful for text plugins to set the value
of an AMD module to a text string (see loader plugins section).

 3a) Is module needed inside a module?

 Yes. A module declaration declares a binding to a static module. A let/var 
 declaration declares a binding to a dynamic value. You only get compile-time 
 linking and scoping with static modules.

In that case, I can see the appeal for what Dmitry mentions in his
reply, just reducing it to:

module thing = some/thing;

Ideally, you could have multiple ones with one module word:

module datePicker = datePicker,
thing = some/thing,
Q = Q;

That would really help with the typing cost seen with traditional
CommonJS modules (require is typed a lot), and better local
identifier to module name alignment than what happens in AMD, where
the dependencies and local var names are separate lists :

define([datePicker, some/thing, Q],
function (datePicker, thing, Q({

});

I have gone to aligning the lists to avoid positioning problems, but I
can see how people could find it ugly. Example:
https://github.com/mozilla/f1/blob/master/web/dev/share/panel/index.js

 3b) Is import needed inside a module?
 For many cases, I think that's fine. But .* is an important convenience for 
 scripting. Also, FWIW, import is already reserved and has symmetry with 
 export, so it seems like a wasted opportunity to fill a natural space in the 
 grammar.

Understood. Thanks to you and Brendan for running that one down. I
like the idea of a let {} = someObject; where it only grabs the own
properties of that object at the time of the call, but I can
appreciate if that is difficult to work out and if it skates too close
to with.

 4) How to optimize
 

 I think this is beyond the scope of ECMAScript.next. People are still 
 figuring out how to optimize delivery, and web performance patterns are still 
 shaking out. ISTM there will be situations where it's more performant to 
 combine many modules into one (which can be done with nested module 
 declarations) and others where it's more performant to conditionally/lazily 
 load modules separately (which can be done with module loaders). I don't 
 currently have a clear picture of how we could build syntactic conveniences 
 or abstractions for doing this, but at least the pieces are there so 
 programmers have the building blocks to start constructing their own tools 
 for doing this.

The experience in RequireJS/AMD and in Dojo land is that different
people/projects want different things: sometimes build all modules
into one file, sometimes build some together in one or a couple of
files and have those sets of modules be usable by some other modules
that are loaded separately.

When you say a built file would be possible with nested module
declarations, that makes it sound like those nested modules may not be
usable/visible by other modules that are not loaded as part of that
built file. It would be interesting to explore that more at some
point.

Using string names as the module names in AMD has helped make it
possible to meet the optimization expectations we have seen so far. So
a module that has a 'some/thing' dependency:

define(my/thing, [some/thing, function (thing){})

when 'some/thing' module is built into the optimized file it has its
string name as the first arg:

define('some/thing', function () {});

I can see this as trickier in Harmony modules, at least for the
examples I have seen, where 'some/thing' needs to be an identifier
like:

module someThing {}

Maybe allow strings instead for the names (I say with blissful syntax
ignorance). Just trying to figure out how to match up string
references to modules in inside a module to a named thing in a built
layer.

 5) Loader plugins
 

 Some of the AMD loaders support loader plugins[7].

 Missing a reference in your bibliography. :)

Sorry, a link would be helpful:
http://requirejs.org/docs/plugins.html

 6) Loader API: multiple modules
 Perhaps. We're trying to get the building blocks in place first. We can 
 figure out what conveniences are needed on top of that.

 BTW, what you're asking for is essentially a concurrent join, which is 
 convenient to express in a new library I'm working on called jsTask:

    let [m1, m2, m3] = yield join(load(m1.js), load(m2.js), load(m3.js));

I like the ideas behind jsTask, although I would rather not type load that much:

let [m1, m2, m3] = yield load([m1.js, m2.js, m3.js]);

Array of modules via require([], function (){}) has been useful in
RequireJS, and has a nice parity with the 

Re: Questions about Harmony Modules

2011-04-02 Thread David Herman
Hi James,

 1) Files as modules do not need module wrapper
 
 Just to confirm, if a JS file contains only a module definition, the
 module X{} wrapper is not needed?

That's correct.
 
 2) Set module export value
 
 
 Is it possible to support setting the value of the module to be a
 function or some other value?

Currently, there's nothing like this in the proposal, but I remember you 
blogged about this before. Harmony modules are static entities, and setting 
their value dynamically would clash with the design goals of static importing 
and exporting.

That said, we could consider adding functionality to make a module callable, to 
address the use case you describe. Thanks for bringing this up.

 3) Are module and import needed inside a module?
 

There are two questions here:

3a) Is module needed inside a module?

Yes. A module declaration declares a binding to a static module. A let/var 
declaration declares a binding to a dynamic value. You only get compile-time 
linking and scoping with static modules.

3b) Is import needed inside a module?

I think the answer here is technically no. You're right that you could 
generally use let/var and destructuring, except for the import M.* case. If we 
allowed you to destructure a runtime expression and dynamically bind all its 
variables, we would be re-introducing `with' into Harmony, which we will never, 
ever, ever do. :)

The other difference -- at least in the current state of the proposal -- is 
that you can't use a `require' form in an ordinary expression, only in the RHS 
of an import/module declaration. This doesn't show up in the Geometry example 
you cited, but if you wanted to import from an external module using `let', you 
would have to use the callback API:

ModuleLoader.load(geometry.js, function(Geometry) {
let { draw } = Geometry;
...
});

(We've talked a little bit about generalizing the `require' form to be an 
expression operator that does a static module load, but I'm not sure whether it 
hangs together.)

 The end goal is trying limit the number of new special things in the
 language the developer needs to learn for modules. Ideally it would
 be: use 'module' to declare an inline module, then use require('')
 inside it to get handles on other modules, and use var/let and
 destructuring as you normally would.

For many cases, I think that's fine. But .* is an important convenience for 
scripting. Also, FWIW, import is already reserved and has symmetry with export, 
so it seems like a wasted opportunity to fill a natural space in the grammar.

 4) How to optimize
 

I think this is beyond the scope of ECMAScript.next. People are still figuring 
out how to optimize delivery, and web performance patterns are still shaking 
out. ISTM there will be situations where it's more performant to combine many 
modules into one (which can be done with nested module declarations) and others 
where it's more performant to conditionally/lazily load modules separately 
(which can be done with module loaders). I don't currently have a clear picture 
of how we could build syntactic conveniences or abstractions for doing this, 
but at least the pieces are there so programmers have the building blocks to 
start constructing their own tools for doing this.

 5) Loader plugins
 
 
 Some of the AMD loaders support loader plugins[7].

Missing a reference in your bibliography. :)

 This allows an AMD
 module to load other types of resources, and a module can treat them
 as a dependency.

I don't know-- I'd be interested to read more on this topic.

 6) Loader API: multiple modules
 
 
 The loader API seems to only allow loading one module at a time with a
 callback (looking at Loader.load). Is there a way to say load these
 three modules, and call this callback when all three are loaded?

Perhaps. We're trying to get the building blocks in place first. We can figure 
out what conveniences are needed on top of that.

BTW, what you're asking for is essentially a concurrent join, which is 
convenient to express in a new library I'm working on called jsTask:

let [m1, m2, m3] = yield join(load(m1.js), load(m2.js), load(m3.js));

 7) Cross-domain script loading
 
 
 Given the modules examples page, it looks like it will be possible to
 load scripts from other domains, just confirming that it will be
 allowed, particularly in the browser.

Yep!

Thanks for the questions,
Dave

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Questions about Harmony Modules

2011-04-02 Thread Brendan Eich
On Apr 2, 2011, at 4:33 PM, David Herman wrote:

 (We've talked a little bit about generalizing the `require' form to be an 
 expression operator that does a static module load, but I'm not sure whether 
 it hangs together.)

I don't see how we can reserve 'require' as a static (compile-time) 
pseudo-function or operator, given that identifier's uses in extant JS.

For Harmony migration we want early errors, but some uses of require would 
look ok even though coded to call something other than the new built-in.


 The end goal is trying limit the number of new special things in the
 language the developer needs to learn for modules. Ideally it would
 be: use 'module' to declare an inline module, then use require('')
 inside it to get handles on other modules, and use var/let and
 destructuring as you normally would.
 
 For many cases, I think that's fine. But .* is an important convenience for 
 scripting. Also, FWIW, import is already reserved and has symmetry with 
 export, so it seems like a wasted opportunity to fill a natural space in the 
 grammar.

I would like to make a stronger case for 'import': it is a static binding form 
new in Harmony that we need for two reasons:

1. To make 'require' on the right a contextual keyword, if used (see above).

2. To make a static binding and fail if there is already a binding of the same 
name.

None of the existing binding forms do both of these. 'const' is closest to 
'import' and satisfies (2), plus it is reserved already -- and variously 
implemented (IIRC Opera equates it with 'var'!). But 'const' does not satisfy 
(1).

Does this sound right?

/be
___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss


Re: Questions about Harmony Modules

2011-04-02 Thread Dave Herman
Fully agree on all counts.

Dave
-- 
Sent from my Android phone with K-9 Mail. Please excuse my brevity.

Brendan Eich bren...@mozilla.com wrote:

On Apr 2, 2011, at 4:33 PM, David Herman wrote:  (We've talked a little bit 
about generalizing the `require' form to be an expression operator that does a 
static module load, but I'm not sure whether it hangs together.) I don't see 
how we can reserve 'require' as a static (compile-time) pseudo-function or 
operator, given that identifier's uses in extant JS. For Harmony migration we 
want early errors, but some uses of require would look ok even though coded 
to call something other than the new built-in.  The end goal is trying limit 
the number of new special things in the  language the developer needs to 
learn for modules. Ideally it would  be: use 'module' to declare an inline 
module, then use require('')  inside it to get handles on other modules, and 
use var/let and  destructuring as you normally would.   For many cases, I 
think that's fine. But .* is an important convenience for scripting. Also, 
FWIW, import is already reserved and has symmetry with export
 , so it
seems like a wasted opportunity to fill a natural space in the grammar. I would 
like to make a stronger case for 'import': it is a static binding form new in 
Harmony that we need for two reasons: 1. To make 'require' on the right a 
contextual keyword, if used (see above). 2. To make a static binding and fail 
if there is already a binding of the same name. None of the existing binding 
forms do both of these. 'const' is closest to 'import' and satisfies (2), plus 
it is reserved already -- and variously implemented (IIRC Opera equates it with 
'var'!). But 'const' does not satisfy (1). Does this sound right? /be

___
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss