Re: Module Comments
On 10 December 2012 05:30, Kevin Smith khs4...@gmail.com wrote: OK, then suppose we have these two separate forms: import x from url; // Bind x to the anonymous export, if defined, otherwise error and import module x from url; // Bind x to the module instance In the vast majority of cases the module keyword above can be inferred correctly at link-time based on whether or not there is an anonymous export in the target module. If it were important for the user to disambiguate in those rare cases, and load the module instance instead of the anonymous export, then she could simply provide the optional module keyword. Does that work? I consider such second-guessing of user intention, which can lead one construct to mean completely different things, harmful. It makes code less readable and more brittle. And again, it's a semantic hack, making the language more complex. I just don't see why it would be worth it, especially since with the right choice of syntax, the two forms of declaration can easily be made equally concise. What's so terrible about using different constructs for different things that you want to avoid it? /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
I consider such second-guessing of user intention, which can lead one construct to mean completely different things, harmful. It makes code less readable and more brittle. And again, it's a semantic hack, making the language more complex. I just don't see why it would be worth it, especially since with the right choice of syntax, the two forms of declaration can easily be made equally concise. That's true. What's so terrible about using different constructs for different things that you want to avoid it? I have an intuition (which may be a holdover from CommonJS modules) that a module is a kind of function which returns either a single binding or a set of named bindings, and the dual-use syntax matches that intuition. But I agree it's conceptually more tidy with two distinct forms. - Kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On 9 December 2012 02:10, Kevin Smith khs4...@gmail.com wrote: So if you didn't set the anonymous binding in some module x.js, what would this do: import x from x.js; Would x be bound to the module instance or would we get a binding error? Since it is just sugar, and supposed to be equivalent to the expansion, you (fortunately) would get an error (statically). /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On 9 December 2012 03:51, Domenic Denicola dome...@domenicdenicola.com wrote: From: Andreas Rossberg [mailto:rossb...@google.com] On 6 December 2012 16:44, Domenic Denicola dome...@domenicdenicola.com wrote: For the record, here's the idea Yehuda and I worked out: https://gist.github.com/1ab3f0daa7b37859ce43 I would *really* appreciate if people read it (it's easy reading, I promise!) and incorporated some of our concerns and ideas into their thinking on module syntax. However, the more radical parts of your proposal (allowing arbitrary export expressions, and arbitrary import patterns) do not work. The problem is that imports are not normal variable assignments. They do not copy values, like normal destructuring, they are aliasing bindings! If you were to allow arbitrary expressions and patterns, then this would imply aliasing of arbitrary object properties. Not only is this a completely new feature, it also is rather questionable -- the aliased location might disappear, because objects are mutable. Thanks for the feedback Andreas; this is really helpful. It took me a while to figure out what you meant by this, but I think I understand now. However, I think that since the bindings are const bindings, the difference between copying and aliasing is unobservable—is that right? No, because what you are aliasing isn't const. Consider: module A { export let x = 4 export function f() { x = 5 } } import {x, f} from A f() print(x) // 5 Moreover, it is still up in the air whether exported mutable bindings should be mutable externally or not. V8, for example, currently allows that, and although it doesn't implement 'import' yet you can access the module directly: A.x = 6 print(A.x) // 6 That is the natural behaviour if you want to be able to use modules as a name spacing mechanism. Same in TypeScript, by the way. You could also consider imports always meaning copying, but then you exporting a variable will no longer be useful. This is the part that made me question whether I understand what you're saying. What do you mean by exporting a variable and useful? I hope the example(s) clarify it. :) /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Module Comments
The problem is that imports are not normal variable assignments. They do not copy values, like normal destructuring, they are aliasing bindings! If you were to allow arbitrary expressions and patterns, then this would imply aliasing of arbitrary object properties. Not only is this a completely new feature, it also is rather questionable -- the aliased location might disappear, because objects are mutable. Could it be structured so that using `export` directly on a variable exported the alias, while using `import { x: [ a, b ] } from A; ` was basically just sugar for `import { x } from A; let [ a, b ] = x;` so that a and b copied not aliased? Example: module A {export let x = { a: 1, b: 2 }; export function f() { x = { a: 3, b: 4 }; };} ... import { x: { a, b }, f } from A;f();print(a); // 1print(b); // 2 ... import { x, f } from A;f();print(x.a); // 3print(x.b); // 4 ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Module Comments
I see my previous email did not format well in the archive. I'm retrying this. (Could someone please give me some formatting tips?) Nathan The problem is that imports are not normal variable assignments. They do not copy values, like normal destructuring, they are aliasing bindings! If you were to allow arbitrary expressions and patterns, then this would imply aliasing of arbitrary object properties. Not only is this a completely new feature, it also is rather questionable -- the aliased location might disappear, because objects are mutable. Could it be structured so that using `export` directly on a variable exported the alias, while using `import { x: [ a, b ] } from A; ` was basically just sugar for `import { x } from A; let [ a, b ] = x;` so that a and b copied not aliased? Example: module A {export let x = { a: 1, b: 2 };export function f() { x = { a: 3, b: 4 }; };} ... import { x: { a, b }, f } from A;f();print(a); // 1print(b); // 2 ... import { x, f } from A;f();print(x.a); // 3print(x.b); // 4 ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On 9 December 2012 15:04, Nathan Wall nathan.w...@live.com wrote: The problem is that imports are not normal variable assignments. They do not copy values, like normal destructuring, they are aliasing bindings! If you were to allow arbitrary expressions and patterns, then this would imply aliasing of arbitrary object properties. Not only is this a completely new feature, it also is rather questionable -- the aliased location might disappear, because objects are mutable. Could it be structured so that using `export` directly on a variable exported the alias, while using `import { x: [ a, b ] } from A; ` was basically just sugar for `import { x } from A; let [ a, b ] = x;` so that a and b copied not aliased? That's what I referred to when I wrote: You could arguably make this saner by interpreting nested patterns in an import as copying, not aliasing, but I think mixing meanings like that would be rather confusing and surprising. So yes, you could do that, but no, I don't think it is a good idea. Your example: import { x: { a, b }, f } from A; f(); print(a); // 1 print(b); // 2 ... import { x, f } from A; f(); print(x.a); // 3 print(x.b); // 4 demonstrates perfectly how it violates the principle of least surprise and can potentially lead to subtle bugs, especially when refactoring. One overarching principle of destructuring should be that all variables in one binding are treated consistently. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Module Comments
Yeah, that makes sense. I agree. Thanks. Nathan On 9 December 2012 15:04, Nathan Wall nathan.w...@live.com wrote: The problem is that imports are not normal variable assignments. They do not copy values, like normal destructuring, they are aliasing bindings! If you were to allow arbitrary expressions and patterns, then this would imply aliasing of arbitrary object properties. Not only is this a completely new feature, it also is rather questionable -- the aliased location might disappear, because objects are mutable. Could it be structured so that using `export` directly on a variable exported the alias, while using `import { x: [ a, b ] } from A; ` was basically just sugar for `import { x } from A; let [ a, b ] = x;` so that a and b copied not aliased? That's what I referred to when I wrote: You could arguably make this saner by interpreting nested patterns in an import as copying, not aliasing, but I think mixing meanings like that would be rather confusing and surprising. So yes, you could do that, but no, I don't think it is a good idea. Your example: import { x: { a, b }, f } from A; f(); print(a); // 1 print(b); // 2 ... import { x, f } from A; f(); print(x.a); // 3 print(x.b); // 4 demonstrates perfectly how it violates the principle of least surprise and can potentially lead to subtle bugs, especially when refactoring. One overarching principle of destructuring should be that all variables in one binding are treated consistently. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
Domenic Denicola wrote: -Original Message- From: Andreas Rossberg [mailto:rossb...@google.com] Sent: Thursday, December 6, 2012 11:31 On 6 December 2012 16:44, Domenic Denicola dome...@domenicdenicola.com wrote: For the record, here's the idea Yehuda and I worked out: https://gist.github.com/1ab3f0daa7b37859ce43 I would *really* appreciate if people read it (it's easy reading, I promise!) and incorporated some of our concerns and ideas into their thinking on module syntax. However, the more radical parts of your proposal (allowing arbitrary export expressions, and arbitrary import patterns) do not work. The problem is that imports are not normal variable assignments. They do not copy values, like normal destructuring, they are aliasing bindings! If you were to allow arbitrary expressions and patterns, then this would imply aliasing of arbitrary object properties. Not only is this a completely new feature, it also is rather questionable -- the aliased location might disappear, because objects are mutable. Thanks for the feedback Andreas; this is really helpful. It took me a while to figure out what you meant by this, but I think I understand now. However, I think that since the bindings are const bindings, the difference between copying and aliasing is unobservable—is that right? Thus the mental model could be copying in all cases, both top-level and deeper. I think the symmetry I am looking for is that import { x: [a, b], f } from foo; should work the same as import foo from foo; const { x: [a, b], f } = foo; No, afaicr that was not the idea, see below. And I realize the linked gist does not introduce const bindings, but instead let bindings; that's easy enough to fix if it's the right path forward. You could also consider imports always meaning copying, but then you exporting a variable will no longer be useful. This is the part that made me question whether I understand what you're saying. What do you mean by exporting a variable and useful? The part about exporting a variable is in fact explaining that it is not about const as you noted above (cp in unix PoV), but really copy of the binding (ln in unix PoV). That is, when you in foo export let FOO = 42; and do import { foo } from foo; in two places, then foo = -1; in one place means it is -1 in all other places as well. I am right in what Andreas meant, then it leads me to the question: is it really meant to be that way? Isn't copying the value (used all over in the language) better way? If I want a shareable value, I export an object that has it as a property. Should export and import be by-reference? Herby ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
Since it is just sugar, and supposed to be equivalent to the expansion, you (fortunately) would get an error (statically). OK, then suppose we have these two separate forms: import x from url; // Bind x to the anonymous export, if defined, otherwise error and import module x from url; // Bind x to the module instance In the vast majority of cases the module keyword above can be inferred correctly at link-time based on whether or not there is an anonymous export in the target module. If it were important for the user to disambiguate in those rare cases, and load the module instance instead of the anonymous export, then she could simply provide the optional module keyword. Does that work? - Kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
So if you didn't set the anonymous binding in some module x.js, what would this do: import x from x.js; Would x be bound to the module instance or would we get a binding error? For module naming, we'd need to have a different syntax. In earlier versions of the proposal that was module x at url Or: import module x from url; Has a nice ring. - Kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Module Comments
-Original Message- From: Andreas Rossberg [mailto:rossb...@google.com] Sent: Thursday, December 6, 2012 11:31 On 6 December 2012 16:44, Domenic Denicola dome...@domenicdenicola.com wrote: For the record, here's the idea Yehuda and I worked out: https://gist.github.com/1ab3f0daa7b37859ce43 I would *really* appreciate if people read it (it's easy reading, I promise!) and incorporated some of our concerns and ideas into their thinking on module syntax. However, the more radical parts of your proposal (allowing arbitrary export expressions, and arbitrary import patterns) do not work. The problem is that imports are not normal variable assignments. They do not copy values, like normal destructuring, they are aliasing bindings! If you were to allow arbitrary expressions and patterns, then this would imply aliasing of arbitrary object properties. Not only is this a completely new feature, it also is rather questionable -- the aliased location might disappear, because objects are mutable. Thanks for the feedback Andreas; this is really helpful. It took me a while to figure out what you meant by this, but I think I understand now. However, I think that since the bindings are const bindings, the difference between copying and aliasing is unobservable—is that right? Thus the mental model could be copying in all cases, both top-level and deeper. I think the symmetry I am looking for is that import { x: [a, b], f } from foo; should work the same as import foo from foo; const { x: [a, b], f } = foo; And I realize the linked gist does not introduce const bindings, but instead let bindings; that's easy enough to fix if it's the right path forward. You could also consider imports always meaning copying, but then you exporting a variable will no longer be useful. This is the part that made me question whether I understand what you're saying. What do you mean by exporting a variable and useful? ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On 6 December 2012 17:54, Kevin Smith khs4...@gmail.com wrote: Note, however, that you still assume some hack in the semantics with the if it exists part. To avoid that, you need to divorce the import syntax from the naming-an-external-module syntax -- which I'd actually prefer anyway, and which was the case in the previous version of the proposal. Could we eliminate the hack on the export side instead? Every module instance has a $DEFAULT export binding. Normally, it is set to the module instance itself. `export = ?` overrides the value of that binding. `import x from y` binds $DEFAULT in y to x. Maybe? Well, in my book, that doesn't count as eliminating the hack, but rather broadening it to all sides. Moreover, it still prevents you from getting a handle on the module itself. In fact, I believe this is pretty much equivalent to what's currently in the proposal. For the record, what I have in mind is similar to your previous suggestion, namely treating export = exp as special syntax for the pseudo declaration export let export = exp (where the second 'export' is meant to act as an identifier/property name). And e.g. import x from url as import {export: x} from url For module naming, we'd need to have a different syntax. In earlier versions of the proposal that was module x at url which would still be usable even for modules using special exports. Note also that using the special export would not be mutually exclusive with having other exports, so in that sense, it is like your $DEFAULT, but far less magic. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On Thu, Dec 6, 2012 at 1:46 PM, Brendan Eich bren...@mozilla.org wrote: David Herman wrote: Cool, definitely want the plain identifier form, it's part of the binding (and destructuring) pattern language. Well, the thing is it isn't consistent with the destructuring meaning: dropping the curlies here means extracting a single export (aka property), which is not what it means in destructuring assignment/binding anywhere else. You are so right. Therefore I think Yehuda et al. (as Andreas affirmed) are spot-on in advocating import foo from foo; // import the singleton export = thing from foo import {bar} from foo; // import the bar export from foo and we don't have a RTL problem. +1 For some reason I thought this is actually how it was working at some point, but I haven't been following as closely as I should. /be __**_ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/**listinfo/es-discusshttps://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Module Comments
Feel free to suggest alternatives, but forgive me if I'm not willing to respond to every opinion on this one. :} How about: import ga as ga; to import the whole module, and import ga as { foo, bar }; to import just parts of the module. I feel like this makes a lot of sense, and is similar to the destructuring pattern. let ga = new Ga(); vs let { foo, bar } = new Ga(); Nathan___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On Dec 5, 2012, at 11:52 PM, Brendan Eich bren...@mozilla.org wrote: ExportDeclaration: export { ExportSpecifier (, ExportSpecifier)* } ; ExportDeclaration: export Identifier (, Identifier)* ; ExportDeclaration: export * from StringLiteral ; Reasonable point, I'll think about that. We do not so limit var, let, or const -- why should we limit export? Ok, it's a bit different (but then import is not, right?). Style enforcement should not be wired into the grammar. If I want to write export {odd, even}, {nat: naturals}; why not? Fairly agnostic about this, given that you can express most combinations within the { ... } form. But I'll think about it. Removing the curlies for this simple case would seem like a win. Another fair point. I think it might've just been a refactoring oversight. Cool, definitely want the plain identifier form, it's part of the binding (and destructuring) pattern language. Well, the thing is it isn't consistent with the destructuring meaning: dropping the curlies here means extracting a single export (aka property), which is not what it means in destructuring assignment/binding anywhere else. But that said, the convenience may well still trump the inconsistency. Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On Thu, Dec 6, 2012 at 8:25 AM, David Herman dher...@mozilla.com wrote: On Dec 5, 2012, at 7:16 PM, Kevin Smith khs4...@gmail.com wrote: 1) export ExportSpecifierSet (, ExportSpecifierSet)* ; This rule seems too permissive. It allows strange combinations like: export x, { y: a.b.c, z }, { j, k }, * from bloop; I think it would be better to flatten it out a little bit: ExportDeclaration: export { ExportSpecifier (, ExportSpecifier)* } ; ExportDeclaration: export Identifier (, Identifier)* ; ExportDeclaration: export * from StringLiteral ; Reasonable point, I'll think about that. 2) Do we need `export *;`? I don't see the point of exporting every declaration in the current module scope. If the programmer wants to export a bunch of stuff, the other forms make that sufficiently easy. Exporting everything encourages bad (de-modular) design. Again, reasonable point. 3) I'm just OK with as. Note that it inverts the position of the string and the binding: import { x } from goo; import ga as ga; Which makes it harder to read when you have a bunch of imports mixed together. It's harder for the eyes to scan back and forth. Yeah, that's the known downside to this syntax. We've been around this block so many times, and it's just one of those things that will end up with bikeshed colored not in paint but in blood. I'm open to alternative suggestions but not to endless discussion (it goes nowhere). The alternative of import ga = ga has the problem of looking like it's saying that ga is a string. The alternatives of import ga = module(ga) or import ga = (module ga) have the problem of making it look like the RHS is an expression. Feel free to suggest alternatives, but forgive me if I'm not willing to respond to every opinion on this one. :} Replace the current `from` form with `of` and use `from` for the single export: import go from ga; // prev: import ga as go import {a: b, b: a} of ta; // prev: import {a: b, b:a} from ta It would even make the common case shorter. :P Or keep the current `from` form and: import go off ga; // prev: import ga as go Or maybe `in`, but it sounds really weird in English as import has an implicit in. Cheers, Jussi 4) Why was this form eliminated? import x from goo; // Note lack of curlies! In an object-oriented application, we're often going to be importing a single thing (the class) from external modules. So we may see long lists like this: import { ClassA } from ClassA.js; import { ClassB } from ClassB.js; import { ClassZ } from ClassZ.js; Removing the curlies for this simple case would seem like a win. Another fair point. I think it might've just been a refactoring oversight. 5) Dynamic exports via `export = ?` could make interop with existing module systems easier. But how does that work? Basic semantics: - The module has one single anonymous export. - Clients can only get access to the export with the as form; there's no way to access it via a named export. - The value of the export is undefined until the RHS is evaluated. 6) Adding .js as the default resolution strategy: I don't think this is tenable. First, there's the practical issue of what happens when someone actually wants to load a resource without a .js extension? They change the resolution hook. Second, there's the philosophical problem of essentially setting up an alternate URL scheme. That's fine for libraries like AMD loaders or YUI. But EcmaScript is a cornerstone of the internet. External resource resolution can't conflict with HTML/CSS/etc. I'll wait till it's fleshed out more didn't last long, eh? ;-) Anyway, I don't really understand this argument but do you think there's much value to a philosophical debate on es-discuss? Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
Well, the thing is it isn't consistent with the destructuring meaning: dropping the curlies here means extracting a single export (aka property), which is not what it means in destructuring assignment/binding anywhere else. But that said, the convenience may well still trump the inconsistency. I think I'd prefer consistency here, as it also allows to get rid of import foo as foo; and replace it with import foo from foo; which keeps the order of import {x,y} from foo and it is all just module-level destructuring (fewer new concepts). Claus ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On Thu, Dec 6, 2012 at 1:25 AM, David Herman dher...@mozilla.com wrote: On Dec 5, 2012, at 7:16 PM, Kevin Smith khs4...@gmail.com wrote: 2) Do we need `export *;`? I don't see the point of exporting every declaration in the current module scope. If the programmer wants to export a bunch of stuff, the other forms make that sufficiently easy. Exporting everything encourages bad (de-modular) design. Again, reasonable point. I *strongly* disagree. There are two important use cases for `export *` -- exporting everything you've defined, for little convenience modules or other quick tasks, and for wrapper modules where you want to export everything you import from somewhere else. Not having it means that you have to write everything explicitly, but more than that means that you end up with annoying busy work when you forget, and have to go figure out where the missing import or export is. I don't see any benefit to leaving it out (unlike `import *`, which was genuinely complex), and I don't think we need to tell programmers what good design is. Sam ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
Summaries with comments: 1) export ExportSpecifierSet (, ExportSpecifierSet)* ; Brendan pointed out that other binding forms allow lists (including the import form), so why not this one? I actually didn't realize that lists are allowed with import: ImportDeclaration ::= import ImportClause (, ImportClause)* ; Fair enough. 2) Do we need `export *;`? Sam pointed out two use cases: 1) Conveniently exporting everything from little convenience modules. I'm not really convinced by this. It's just so easy to export things by adding the export keyword. 2) Re-exporting a collection of imports from other sources. This is better, at least in the case where you want to import a well-defined set of bindings and then re-export those same bindings later. Without `export *;`, you'd have to keep those binding lists in sync. Sounds reasonable to me. 3) I'm just OK with as. Note that it inverts the position of the string and the binding: Claus and Matthew suggested using the no-curlies form instead: import ga from ga; Dave responded by pointing out that we don't want from to have overloaded semantics. I actually think this form has potential, because it further aligns import with the other binding forms: var a = x; var { b } = y; // Symmetry! import a from x; import { b } from y; 5) Dynamic exports via `export = ?` could make interop with existing module systems easier. But how does that work? Dave gave an outline. I'm liking this. What are the downsides, if any? 6) Adding .js as the default resolution strategy: Dave responded that a custom resolution hook would be required for resources that don't end in .js. While that certainly works for current loader libraries, can we really mandate a js extension for all module URLs, forever? Because this default will effectively mandate that. Imagine if such a mandate came from CSS. URLs are a backbone concept of the internet and we shouldn't go fiddling with it. Dave also responded: I'll wait till it's fleshed out more didn't last long, eh? ;-) Anyway, I don't really understand this argument but do you think there's much value to a philosophical debate on es-discuss? Well, I practice Olympian levels of patience with my four small children day in and day out, so you'll have to forgive me if I've got none left over for you, good sir. ; ) - Kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On Thu, Dec 6, 2012 at 9:42 AM, Kevin Smith khs4...@gmail.com wrote: Dave responded by pointing out that we don't want from to have overloaded semantics. I actually think this form has potential, because it further aligns import with the other binding forms: var a = x; var { b } = y; // Symmetry! import a from x; import { b } from y; +1 This also matches what Yehuda and Domenic proposed a few weeks ago. -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
+1 Compared to Node.js, I love ES6 exports, but Node.js module imports are easier to understand. Claus’ suggestion would make `import` similar to `let` and people could basically think of modules as objects. On Dec 6, 2012, at 10:41 , Claus Reinke claus.rei...@talk21.com wrote: Well, the thing is it isn't consistent with the destructuring meaning: dropping the curlies here means extracting a single export (aka property), which is not what it means in destructuring assignment/binding anywhere else. But that said, the convenience may well still trump the inconsistency. I think I'd prefer consistency here, as it also allows to get rid of import foo as foo; and replace it with import foo from foo; which keeps the order of import {x,y} from foo and it is all just module-level destructuring (fewer new concepts). -- Dr. Axel Rauschmayer a...@rauschma.de home: rauschma.de twitter: twitter.com/rauschma blog: 2ality.com ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Module Comments
For the record, here's the idea Yehuda and I worked out: https://gist.github.com/1ab3f0daa7b37859ce43 I would *really* appreciate if people read it (it's easy reading, I promise!) and incorporated some of our concerns and ideas into their thinking on module syntax. In general, it tries to eliminate the ExportSpecifierSet and ImportSpecifierSet microsyntaxes in favor of standard object literal/destructuring forms, respectively. It also made export and import syntax symmetric. It apparently failed to get much traction among committee members, mainly because of objections to our reformation of the export-side syntax. (Second-hand info.) E.g. the current export function foo() { } was preferred to the proposed export { foo() { } }, and---less aesthetically---our special behavior for ObjectLiteral expressions over other expressions was a bit weird. I still think the import-side reformation is important and stand by everything in the proposal in that regard. As mentioned in other messages in this thread, the current form is confusingly dual-natured. And I maintain that the incomplete semi-destructuring microsyntax of ImportSpecifierSet adds a lot of cognitive burden. If we can start by fixing the import side, I have some other ideas on how to make the export side better that hopefully will be more appealing to the committee. But I don't want to try proposing those yet until we can get the buy-in on fixing import. From: es-discuss-boun...@mozilla.org [es-discuss-boun...@mozilla.org] on behalf of Erik Arvidsson [erik.arvids...@gmail.com] Sent: Thursday, December 06, 2012 09:54 To: Kevin Smith Cc: es-discuss Subject: Re: Module Comments On Thu, Dec 6, 2012 at 9:42 AM, Kevin Smith khs4...@gmail.commailto:khs4...@gmail.com wrote: Dave responded by pointing out that we don't want from to have overloaded semantics. I actually think this form has potential, because it further aligns import with the other binding forms: var a = x; var { b } = y; // Symmetry! import a from x; import { b } from y; +1 This also matches what Yehuda and Domenic proposed a few weeks ago. -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On 6 December 2012 15:42, Kevin Smith khs4...@gmail.com wrote: 5) Dynamic exports via `export = ?` could make interop with existing module systems easier. But how does that work? Dave gave an outline. I'm liking this. What are the downsides, if any? The downside is that it introduces a severe anomaly into the module semantics (a module which actually has no instance). I could live with this feature if we were to find a way to explain it in terms of simple syntactic sugar on both the import and export side, but screwing and complicating the semantics for minor syntactic convenience is not something I am particularly fond of. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
One plausible variant to our proposal that might be easier to swallow (as it doesn't have the special-cased ObjectLiteral problem) is: - Replace `export ExportSpecifierSet` with `export ObjectLiteral` for static exports - Allow `export = foo` (or something like it) for single exports - Unify the import syntax to support the full destructuring syntax and to work on both static and single exports This retains the advantages of reducing micro-syntax and reforming import without forcing an awkward special-casing of `export ObjectLiteral` On Thu, Dec 6, 2012 at 7:44 AM, Domenic Denicola dome...@domenicdenicola.com wrote: For the record, here's the idea Yehuda and I worked out: https://gist.github.com/1ab3f0daa7b37859ce43 I would *really* appreciate if people read it (it's easy reading, I promise!) and incorporated some of our concerns and ideas into their thinking on module syntax. In general, it tries to eliminate the ExportSpecifierSet and ImportSpecifierSet microsyntaxes in favor of standard object literal/destructuring forms, respectively. It also made export and import syntax symmetric. It apparently failed to get much traction among committee members, mainly because of objections to our reformation of the export-side syntax. (Second-hand info.) E.g. the current export function foo() { } was preferred to the proposed export { foo() { } }, and---less aesthetically---our special behavior for ObjectLiteral expressions over other expressions was a bit weird. I still think the import-side reformation is important and stand by everything in the proposal in that regard. As mentioned in other messages in this thread, the current form is confusingly dual-natured. And I maintain that the incomplete semi-destructuring microsyntax of ImportSpecifierSet adds a lot of cognitive burden. If we can start by fixing the import side, I have some other ideas on how to make the export side better that hopefully will be more appealing to the committee. But I don't want to try proposing those yet until we can get the buy-in on fixing import. -- *From:* es-discuss-boun...@mozilla.org [es-discuss-boun...@mozilla.org] on behalf of Erik Arvidsson [erik.arvids...@gmail.com] *Sent:* Thursday, December 06, 2012 09:54 *To:* Kevin Smith *Cc:* es-discuss *Subject:* Re: Module Comments On Thu, Dec 6, 2012 at 9:42 AM, Kevin Smith khs4...@gmail.com wrote: Dave responded by pointing out that we don't want from to have overloaded semantics. I actually think this form has potential, because it further aligns import with the other binding forms: var a = x; var { b } = y; // Symmetry! import a from x; import { b } from y; +1 This also matches what Yehuda and Domenic proposed a few weeks ago. -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Yehuda Katz (ph) 718.877.1325 ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On 6 December 2012 16:44, Domenic Denicola dome...@domenicdenicola.com wrote: For the record, here's the idea Yehuda and I worked out: https://gist.github.com/1ab3f0daa7b37859ce43 I would *really* appreciate if people read it (it's easy reading, I promise!) and incorporated some of our concerns and ideas into their thinking on module syntax. I strongly agree with having the import x from ... import {x, y} from ... symmetry and consistent binding on the left. However, the more radical parts of your proposal (allowing arbitrary export expressions, and arbitrary import patterns) do not work. The problem is that imports are not normal variable assignments. They do not copy values, like normal destructuring, they are aliasing bindings! If you were to allow arbitrary expressions and patterns, then this would imply aliasing of arbitrary object properties. Not only is this a completely new feature, it also is rather questionable -- the aliased location might disappear, because objects are mutable. Consider: module A { let o = { x: [1, 2], f() { o.x = 666 } } export o } import {x: [a, b], f} from A a = 3 // is this supposed to modify the array? f() print(a) // x is no longer an array, a doesn't even exist In other words, what you are proposing has no longer anything to do with static scoping. You could arguably make this saner by interpreting nested patterns in an import as copying, not aliasing, but I think mixing meanings like that would be rather confusing and surprising. You could also consider imports always meaning copying, but then you exporting a variable will no longer be useful. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
The downside is that it introduces a severe anomaly into the module semantics (a module which actually has no instance). I could live with this feature if we were to find a way to explain it in terms of simple syntactic sugar on both the import and export side, but screwing and complicating the semantics for minor syntactic convenience is not something I am particularly fond of. What if this: export = boo; Actually creates a static export with some exotic name, say __DEFAULT__ (for the sake of argument) and initializes it to the value boo. And this form: import boo from boo.js; Creates a binding to __DEFAULT__ in boo.js, if it exists, or to the module instance of boo.js otherwise. Would that work as a desugaring? - Kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On 6 December 2012 17:33, Kevin Smith khs4...@gmail.com wrote: The downside is that it introduces a severe anomaly into the module semantics (a module which actually has no instance). I could live with this feature if we were to find a way to explain it in terms of simple syntactic sugar on both the import and export side, but screwing and complicating the semantics for minor syntactic convenience is not something I am particularly fond of. What if this: export = boo; Actually creates a static export with some exotic name, say __DEFAULT__ (for the sake of argument) and initializes it to the value boo. And this form: import boo from boo.js; Creates a binding to __DEFAULT__ in boo.js, if it exists, or to the module instance of boo.js otherwise. Would that work as a desugaring? I suggested something along these lines at some point in the past, but there were some concerns with it that, unfortunately, I do not remember. Maybe it can be resolved. Note, however, that you still assume some hack in the semantics with the if it exists part. To avoid that, you need to divorce the import syntax from the naming-an-external-module syntax -- which I'd actually prefer anyway, and which was the case in the previous version of the proposal. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
What about trying it the other way, flip everything. import foo as bar; import foo as { baz } On Thu, Dec 6, 2012 at 8:42 AM, Andreas Rossberg rossb...@google.comwrote: On 6 December 2012 17:33, Kevin Smith khs4...@gmail.com wrote: The downside is that it introduces a severe anomaly into the module semantics (a module which actually has no instance). I could live with this feature if we were to find a way to explain it in terms of simple syntactic sugar on both the import and export side, but screwing and complicating the semantics for minor syntactic convenience is not something I am particularly fond of. What if this: export = boo; Actually creates a static export with some exotic name, say __DEFAULT__ (for the sake of argument) and initializes it to the value boo. And this form: import boo from boo.js; Creates a binding to __DEFAULT__ in boo.js, if it exists, or to the module instance of boo.js otherwise. Would that work as a desugaring? I suggested something along these lines at some point in the past, but there were some concerns with it that, unfortunately, I do not remember. Maybe it can be resolved. Note, however, that you still assume some hack in the semantics with the if it exists part. To avoid that, you need to divorce the import syntax from the naming-an-external-module syntax -- which I'd actually prefer anyway, and which was the case in the previous version of the proposal. /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- - Matthew Robb ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On 6 December 2012 17:46, Matthew Robb matthewwr...@gmail.com wrote: What about trying it the other way, flip everything. import foo as bar; import foo as { baz } Hm, I don't understand. What would that solve? /Andreas ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
Well the argument being that as it stands it's inconsistent having the identifier on the RHS for import from and LHS in import as: import baz from foo; import foo as foo; I'm just throwing out simple options for solving that inconsistency. Possibly even thinking about them as declarations makes the simplest sense anyway: var foo = import foo; var { baz } = import foo; On Thu, Dec 6, 2012 at 8:49 AM, Andreas Rossberg rossb...@google.comwrote: On 6 December 2012 17:46, Matthew Robb matthewwr...@gmail.com wrote: What about trying it the other way, flip everything. import foo as bar; import foo as { baz } Hm, I don't understand. What would that solve? /Andreas -- - Matthew Robb ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
Note, however, that you still assume some hack in the semantics with the if it exists part. To avoid that, you need to divorce the import syntax from the naming-an-external-module syntax -- which I'd actually prefer anyway, and which was the case in the previous version of the proposal. Could we eliminate the hack on the export side instead? Every module instance has a $DEFAULT export binding. Normally, it is set to the module instance itself. `export = ?` overrides the value of that binding. `import x from y` binds $DEFAULT in y to x. Maybe? - Kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
Every module instance has a $DEFAULT export binding. Normally, it is set to the module instance itself. `export = ?` overrides the value of that binding. `import x from y` binds $DEFAULT in y to x. Maybe? That would be how Node.js does. For those unfamiliar with how it works, it's basically like this var mod = { exports: {} }; (function(module, exports){ ... })(mod, mod.exports); So if you assign things to the default exports like exports.firstExport = value; exports.secondExport = value; You're assigning to the default provided export object. But since you also have access to the container (module) you can opt to fully overwrite it module.exports = singleExportedThing; If you added things to exports and then overwrote module.exports with a new value, those initial exports will not be visible as exports because the original export object is overwritten. exports.willBeOverwritten = true; module.exports = singleExportedThing; So the single export route is opt-in, but it's opted into in the large majority of cases. On Thu, Dec 6, 2012 at 11:54 AM, Kevin Smith khs4...@gmail.com wrote: Note, however, that you still assume some hack in the semantics with the if it exists part. To avoid that, you need to divorce the import syntax from the naming-an-external-module syntax -- which I'd actually prefer anyway, and which was the case in the previous version of the proposal. Could we eliminate the hack on the export side instead? Every module instance has a $DEFAULT export binding. Normally, it is set to the module instance itself. `export = ?` overrides the value of that binding. `import x from y` binds $DEFAULT in y to x. Maybe? - Kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
David Herman wrote: Cool, definitely want the plain identifier form, it's part of the binding (and destructuring) pattern language. Well, the thing is it isn't consistent with the destructuring meaning: dropping the curlies here means extracting a single export (aka property), which is not what it means in destructuring assignment/binding anywhere else. You are so right. Therefore I think Yehuda et al. (as Andreas affirmed) are spot-on in advocating import foo from foo; // import the singleton export = thing from foo import {bar} from foo; // import the bar export from foo and we don't have a RTL problem. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Module Comments
I've had a look at the changes to the modules wiki page [1]. I'm liking the syntax changes quite a lot actually, but I have a couple of comments: 1) export ExportSpecifierSet (, ExportSpecifierSet)* ; This rule seems too permissive. It allows strange combinations like: export x, { y: a.b.c, z }, { j, k }, * from bloop; I think it would be better to flatten it out a little bit: ExportDeclaration: export { ExportSpecifier (, ExportSpecifier)* } ; ExportDeclaration: export Identifier (, Identifier)* ; ExportDeclaration: export * from StringLiteral ; 2) Do we need `export *;`? I don't see the point of exporting every declaration in the current module scope. If the programmer wants to export a bunch of stuff, the other forms make that sufficiently easy. Exporting everything encourages bad (de-modular) design. 3) I'm just OK with as. Note that it inverts the position of the string and the binding: import { x } from goo; import ga as ga; Which makes it harder to read when you have a bunch of imports mixed together. It's harder for the eyes to scan back and forth. 4) Why was this form eliminated? import x from goo; // Note lack of curlies! In an object-oriented application, we're often going to be importing a single thing (the class) from external modules. So we may see long lists like this: import { ClassA } from ClassA.js; import { ClassB } from ClassB.js; import { ClassZ } from ClassZ.js; Removing the curlies for this simple case would seem like a win. 5) Dynamic exports via `export = ?` could make interop with existing module systems easier. But how does that work? 6) Adding .js as the default resolution strategy: I don't think this is tenable. First, there's the practical issue of what happens when someone actually wants to load a resource without a .js extension? Second, there's the philosophical problem of essentially setting up an alternate URL scheme. That's fine for libraries like AMD loaders or YUI. But EcmaScript is a cornerstone of the internet. External resource resolution can't conflict with HTML/CSS/etc. - Kevin [1] http://wiki.ecmascript.org/doku.php?id=harmony:modules ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
David Herman wrote: On Dec 5, 2012, at 7:16 PM, Kevin Smithkhs4...@gmail.com wrote: 3) I'm just OK with as. Note that it inverts the position of the string and the binding: import { x } from goo; import ga as ga; Which makes it harder to read when you have a bunch of imports mixed together. It's harder for the eyes to scan back and forth. Yeah, that's the known downside to this syntax. We've been around this block so many times, and it's just one of those things that will end up with bikeshed colored not in paint but in blood. I'm open to alternative suggestions but not to endless discussion (it goes nowhere). The alternative of import ga = ga has the problem of looking like it's saying that ga is a string. The alternatives of import ga = module(ga) or import ga = (module ga) have the problem of making it look like the RHS is an expression. Feel free to suggest alternatives, but forgive me if I'm not willing to respond to every opinion on this one. :} import x from goo; import ga for ga; import x from goo; import ga ga; Dave Herby ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On Dec 5, 2012, at 10:41 PM, Herby Vojčík he...@mailbox.sk wrote: import x from goo; Already taken. You can't use one syntax to mean two things. import ga for ga; That doesn't have any correspondence to its meaning in English. import x from goo; That's identical to your first suggestion. import ga ga; Awkward. Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
David Herman wrote: On Dec 5, 2012, at 10:41 PM, Herby Vojčíkhe...@mailbox.sk wrote: import x from goo; Already taken. You can't use one syntax to mean two things. I don't. These were included to show the two syntaxes (existing from and proposed instead-of-as grouped together; to see how they look mixed). import ga for ga; That doesn't have any correspondence to its meaning in English. It does. import ga for (the whole module) ga. Alternative was `import ga for module ga;`. import x from goo; That's identical to your first suggestion. Same as above. import ga ga; Awkward. Dave Herby ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
I don't see why you can't treat it like this: import local accessor from resource import ga from ga; If you want to import specific exports then use curlies or dot notation import ga.foo from ga; import { foo } from ga; On Wed, Dec 5, 2012 at 11:05 PM, Herby Vojčík he...@mailbox.sk wrote: David Herman wrote: On Dec 5, 2012, at 10:41 PM, Herby Vojčíkhe...@mailbox.sk wrote: import x from goo; Already taken. You can't use one syntax to mean two things. I don't. These were included to show the two syntaxes (existing from and proposed instead-of-as grouped together; to see how they look mixed). import ga for ga; That doesn't have any correspondence to its meaning in English. It does. import ga for (the whole module) ga. Alternative was `import ga for module ga;`. import x from goo; That's identical to your first suggestion. Same as above. import ga ga; Awkward. Dave Herby __**_ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/**listinfo/es-discusshttps://mail.mozilla.org/listinfo/es-discuss -- - Matthew Robb ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On Dec 5, 2012, at 11:05 PM, Herby Vojčík he...@mailbox.sk wrote: import x from goo; Already taken. You can't use one syntax to mean two things. I don't. These were included to show the two syntaxes (existing from and proposed instead-of-as grouped together; to see how they look mixed). Ah, my misunderstanding, thanks for clarifying. import ga for ga; That doesn't have any correspondence to its meaning in English. It does. import ga for (the whole module) ga. Alternative was `import ga for module ga;`. It doesn't work, at least not with the verb import. What you're trying to say is import the module 'ga' with the name ga as its local binding. You're not importing the *binding itself*. Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
On Dec 5, 2012, at 11:09 PM, Matthew Robb matthewwr...@gmail.com wrote: I don't see why you can't treat it like this: import local accessor from resource import ga from ga; We really don't want `from` to be dual-purposed to sometimes mean the whole module itself, and sometimes extracting exports from the module. The syntax should make it absolutely clear which is which. If you want to import specific exports then use curlies or dot notation import ga.foo from ga; That's really weird. You essentially are allowing any identifier whatsoever to the left of the dot. Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Module Comments
David Herman wrote: On Dec 5, 2012, at 7:16 PM, Kevin Smithkhs4...@gmail.com wrote: 1) export ExportSpecifierSet (, ExportSpecifierSet)* ; This rule seems too permissive. It allows strange combinations like: export x, { y: a.b.c, z }, { j, k }, * from bloop; I think it would be better to flatten it out a little bit: ExportDeclaration: export { ExportSpecifier (, ExportSpecifier)* } ; ExportDeclaration: export Identifier (, Identifier)* ; ExportDeclaration: export * from StringLiteral ; Reasonable point, I'll think about that. We do not so limit var, let, or const -- why should we limit export? Ok, it's a bit different (but then import is not, right?). Style enforcement should not be wired into the grammar. If I want to write export {odd, even}, {nat: naturals}; why not? Skipping 'as' reversal, that is a tough one! The export = ... special form does not suggest a better syntax, alas. 4) Why was this form eliminated? import x from goo; // Note lack of curlies! In an object-oriented application, we're often going to be importing a single thing (the class) from external modules. So we may see long lists like this: import { ClassA } from ClassA.js; import { ClassB } from ClassB.js; import { ClassZ } from ClassZ.js; Removing the curlies for this simple case would seem like a win. Another fair point. I think it might've just been a refactoring oversight. Cool, definitely want the plain identifier form, it's part of the binding (and destructuring) pattern language. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss