ModuleImport
Thanks to everyone for working through the issues around ModuleImport. I know it's been frustrating, but the discussions have really helped clarify the key constraints. ## Constraints First, let me restate the most important arguments. In favor of removal: * **The syntactic distinction between ModuleImport and default import is vague.** We've consistently seen confusion between the semantics of ModuleImport and default export. While certainly some of the confusion might be chalked up to misinformation and lack of documentation, we've seen people be confused by this even when correctly explained the semantics. The problem with the syntax is that the only visual distinction is the initial keyword (`module` vs `import`), and it's not clear from that keyword which concept you're talking about. (Once you've internalized the structure of module instance objects, you get a hint from the `module` keyword, but that doesn't help people who are just learning the system, particularly if they're already familiar with other JS module systems.) Against removal: * **Without ModuleImport, authors of multi-export modules would be pressured to circumvent the named exports functionality.** Without ModuleImport, clients of multi-export modules have two options. Either they use named import: ```js import { readFile, writeFile } from fs; ``` or if they want to explicitly namespace those functions, they have to use the dynamic API: ```js import fs; // state the dependency var fs = this.get(fs); ``` That's inconvenient, confusing, and makes you feel like you're stepping outside the normal usage patterns intended for the system. Since this is a choice forced on the clients of a module, the module author will feel pressure to circumvent the named export feature altogether and instead export a default object with all the properties. This is bad -- it creates pressure for people to abandon part of the module system. ## Conclusion Here's the conclusion I've come to based on all of the above. * **We need a form like ModuleImport.** As many have said, clients of named-export modules need the freedom to choose whether to explicitly namespace those imports, and they need a syntax that doesn't feel like they've stepped outside the normal system. * **The current syntax of ModuleImport is wrong.** The confusion reported in developer feedback is real, and it's important. * **The syntax should still favor default import.** ES6 favors the single/default export style, and gives the sweetest syntax to importing the default. Importing named exports can and even should be slightly less concise. * **A better ModuleImport syntax is possible, and we should settle it soon.** I'll propose a better ModuleImport syntax below. Syntax being syntax, everyone will of course unsheathe their bikeshed paintbrush. That's OK. The champions will keep it from going on unbounded and help settle the debate, and we'll make sure to capture the conclusion in the next TC39 meeting. I do acknowledge the concerns about reopening topics for debate and delay. But given the usability feedback, I think this case is worth fixing. We should resolve it for ES6, perhaps in part because it's less editorial work to change the ModuleImport production than to defer it, but more because I don't want to delay the resolution so that implementations can ship the better syntax. But keep in mind it doesn't matter what spec it lands in as long as implementations are shipping it. We're still in the early days of transpiler implementations, and there are no native implementations of modules yet. So there's time, as long as we don't let the bikeshed go on forever. So let's get to it! ## Proposal OK, so we're talking about a better syntax for importing a module and binding its named exports to a variable (as distinct from importing a module and binding its default export to a variable). Here's my proposal: ```js import * as fs from fs; // importing the named exports as an object import Dict from dict; // importing a default export, same as ever ``` Why is this better? Because it dovetails with the named export syntax, **which makes it clear that it's binding `fs` to the named exports.** It saves the reader from having to know that the module instance object is not the same thing as the default export. So there you have it... Feedback welcome, and as always we'll collect it all, weigh it, and try to shepherd consensus. Oh, and just to put parameters on the discussion: * **I'm not proposing additional new import forms.** If this syntax is future-compatible with other possible syntactic forms, that's great, but that's not what we're discussing. * **I'm not interested in discussing changes to the rest of the module syntax.** This isn't the time or place to redesign the whole system. * **The `this` binding in modules is a separate topic.** The `this` binding in modules can be discussed independently of this topic. tl;dr we're
Re: ModuleImport
That’s a good solution. Logically, `import { * } from fs` may make more sense, but I prefer the “unbraced” asterisk, because it results in less clutter. Does the proposed syntax clash with `export * FromClause` (which, I’m assuming, re-exports everything, not just the named exports)? I’d prefer it if named exports and a default export were mutually exclusive, but I understand that is off the table(?) Which is also fine with me… Axel On Jun 19, 2014, at 10:15 , David Herman dher...@mozilla.com wrote: ## Proposal OK, so we're talking about a better syntax for importing a module and binding its named exports to a variable (as distinct from importing a module and binding its default export to a variable). Here's my proposal: ```js import * as fs from fs; // importing the named exports as an object import Dict from dict; // importing a default export, same as ever ``` -- Dr. Axel Rauschmayer a...@rauschma.de rauschma.de ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
On Jun 19, 2014, at 2:03 AM, Axel Rauschmayer a...@rauschma.de wrote: Does the proposed syntax clash with `export * FromClause` (which, I’m assuming, re-exports everything, not just the named exports)? No inconsistency; it imports everything. Exactly the same semantics as always, just a change in surface syntax. Remember that the module instance object contains all named exports, but the default export is simply an export with the name `default`. Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Standard builtins' prototypes and toString
On Thu, Jun 19, 2014 at 1:39 AM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: On Jun 18, 2014, at 4:12 PM, Brendan Eich wrote: Allen Wirfs-Brock wrote: The spec. current says throw for this Symbol.prototype case. The (reasonable) opposing view is that toString should never throw. Other than the protoype-is-not-an-instance it all about unlikely edge cases where toString methods are applied to the wrong kind of object. js Object.create(null).toString() typein:1:0 TypeError: Object.create(...).toString is not a function It happens. Better to catch that error (Symbol.prototype flowing into an implicit conversion) early? which is pretty much the approach the ES6 spec. has taken WRT toString up to now. Tension between catching invalid iplicit toString conversions and reliable toString for debugging. I'd posit that there are three different cases for toString: 1) (explictly or implicitly) calling foo.toString, where `foo` is any of the objects that, by default, exist in a JS global without any user code having run 2) (explicitly or implicitly) calling foo.toString, where `foo` is some content script-generated object 3) explicitly calling bar.toString.call(foo), where `foo` and `bar` are arbitrary objects The current (ES5) state of things is that 1) can never throw, while both 2) and 3) might. The current ES6 draft would move 1) over into the latter camp. I think *that* is the crucial thing to prevent. It's just wrong for the language to essentially say here's a bunch of objects. They have methods. But don't call all of them. Finding out which ones aren't allowed to be called is left as an excercise to the reader. Theoretically, Scott's #d still hold the most appeal to me. However, I don't think it works in a multi-Realm world, hence theoretically. Given that, it's #b or #c, where, again, I don't much care which one it'll be. At any rate, run time tools can really depend upon toString working, They probably should use something like: function reliableToString(obj) { try {return obj.toString()} catch (e) { try {return {}.toString.call(obj)} catch (f) { return [ object ???]} } } } True. It's not clear to me that the web as a whole knows this, though, and the current state of the spec might teach it the hard way. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
Thanks, Dave, for bringing that up, it shows you're open for feedback. That said (bikeshed begins), what's wrong with: ```js import fs as fs; ``` ? I feel that a lot of effort went in ES6 into reducing boilerplate via e.g. arrow functions, classes etc. but if you start with Node's require, this adds clutter. Compare these 3 forms of importing all the module lodash bindings to an object _: ```js var _ = require(lodash); // Node import * as _ from lodash; // Dave's syntax import lodash as _; ``` ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
This is a key sentence in David’s proposal: “ES6 favors the single/default export style, and gives the sweetest syntax to importing the default. Importing named exports can and even should be slightly less concise.” On Jun 19, 2014, at 12:31 , Michał Gołębiowski m.go...@gmail.com wrote: Thanks, Dave, for bringing that up, it shows you're open for feedback. That said (bikeshed begins), what's wrong with: ```js import fs as fs; ``` ? I feel that a lot of effort went in ES6 into reducing boilerplate via e.g. arrow functions, classes etc. but if you start with Node's require, this adds clutter. Compare these 3 forms of importing all the module lodash bindings to an object _: ```js var _ = require(lodash); // Node import * as _ from lodash; // Dave's syntax import lodash as _; ``` -- Dr. Axel Rauschmayer a...@rauschma.de rauschma.de ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
One other option could be for import name from 'path' to resolve to the module body there is no default export, thanks to the static analysis you'll always know when default is present. The import 'path'/this.get syntax is a lot less burdensome if it's only required by edge cases like needing both default export and all the named ones. On Jun 19, 2014 6:32 AM, Michał Gołębiowski m.go...@gmail.com wrote: Thanks, Dave, for bringing that up, it shows you're open for feedback. That said (bikeshed begins), what's wrong with: ```js import fs as fs; ``` ? I feel that a lot of effort went in ES6 into reducing boilerplate via e.g. arrow functions, classes etc. but if you start with Node's require, this adds clutter. Compare these 3 forms of importing all the module lodash bindings to an object _: ```js var _ = require(lodash); // Node import * as _ from lodash; // Dave's syntax import lodash as _; ``` ___ 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: ModuleImport
On Thu, Jun 19, 2014 at 12:40 PM, Axel Rauschmayer a...@rauschma.de wrote: This is a key sentence in David’s proposal: “ES6 favors the single/default export style, and gives the sweetest syntax to importing the default. Importing named exports can and even should be slightly less concise.” There are a lot of large modules that will not disappear overnight. I assume ES6's recommendation for such things (Node's fs module, Lo-Dash) is to make those container objects default exports? -- Michał Gołębiowski ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
What is the behavior if a module doesn't define a default export and the syntax for importing the default export is used? What is the behavior if a module only defines a default export and the syntax for importing named imports is used? --- R. Mark Volkmann Object Computing, Inc. On Jun 19, 2014, at 3:15 AM, David Herman dher...@mozilla.com wrote: Thanks to everyone for working through the issues around ModuleImport. I know it's been frustrating, but the discussions have really helped clarify the key constraints. ## Constraints First, let me restate the most important arguments. In favor of removal: * **The syntactic distinction between ModuleImport and default import is vague.** We've consistently seen confusion between the semantics of ModuleImport and default export. While certainly some of the confusion might be chalked up to misinformation and lack of documentation, we've seen people be confused by this even when correctly explained the semantics. The problem with the syntax is that the only visual distinction is the initial keyword (`module` vs `import`), and it's not clear from that keyword which concept you're talking about. (Once you've internalized the structure of module instance objects, you get a hint from the `module` keyword, but that doesn't help people who are just learning the system, particularly if they're already familiar with other JS module systems.) Against removal: * **Without ModuleImport, authors of multi-export modules would be pressured to circumvent the named exports functionality.** Without ModuleImport, clients of multi-export modules have two options. Either they use named import: ```js import { readFile, writeFile } from fs; ``` or if they want to explicitly namespace those functions, they have to use the dynamic API: ```js import fs; // state the dependency var fs = this.get(fs); ``` That's inconvenient, confusing, and makes you feel like you're stepping outside the normal usage patterns intended for the system. Since this is a choice forced on the clients of a module, the module author will feel pressure to circumvent the named export feature altogether and instead export a default object with all the properties. This is bad -- it creates pressure for people to abandon part of the module system. ## Conclusion Here's the conclusion I've come to based on all of the above. * **We need a form like ModuleImport.** As many have said, clients of named-export modules need the freedom to choose whether to explicitly namespace those imports, and they need a syntax that doesn't feel like they've stepped outside the normal system. * **The current syntax of ModuleImport is wrong.** The confusion reported in developer feedback is real, and it's important. * **The syntax should still favor default import.** ES6 favors the single/default export style, and gives the sweetest syntax to importing the default. Importing named exports can and even should be slightly less concise. * **A better ModuleImport syntax is possible, and we should settle it soon.** I'll propose a better ModuleImport syntax below. Syntax being syntax, everyone will of course unsheathe their bikeshed paintbrush. That's OK. The champions will keep it from going on unbounded and help settle the debate, and we'll make sure to capture the conclusion in the next TC39 meeting. I do acknowledge the concerns about reopening topics for debate and delay. But given the usability feedback, I think this case is worth fixing. We should resolve it for ES6, perhaps in part because it's less editorial work to change the ModuleImport production than to defer it, but more because I don't want to delay the resolution so that implementations can ship the better syntax. But keep in mind it doesn't matter what spec it lands in as long as implementations are shipping it. We're still in the early days of transpiler implementations, and there are no native implementations of modules yet. So there's time, as long as we don't let the bikeshed go on forever. So let's get to it! ## Proposal OK, so we're talking about a better syntax for importing a module and binding its named exports to a variable (as distinct from importing a module and binding its default export to a variable). Here's my proposal: ```js import * as fs from fs; // importing the named exports as an object import Dict from dict; // importing a default export, same as ever ``` Why is this better? Because it dovetails with the named export syntax, **which makes it clear that it's binding `fs` to the named exports.** It saves the reader from having to know that the module instance object is not the same thing as the default export. So there you have it... Feedback welcome, and as always we'll collect it all, weigh it, and try to shepherd consensus. Oh, and just to put parameters on the discussion: * **I'm
Re: @@new
On Wed, Jun 18, 2014 at 5:29 PM, Kevin Smith zenpars...@gmail.com wrote: I think Allen's suggestion of providing constructor arguments to @@create is promising. That would allow the implementation to allocate and initialize an object in one go, if desired. That seems to embody the advantages of fusing initialization and allocation, without the headache for the user. Never mind, that doesn't work. Sorry for the noise. I'd like to understand. Why doesn't it work? -j ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: @@new
I'd like to understand. Why doesn't it work? Allen wondered the same, so I'll just paste my reply to him: So I was a little embarrassed about not thinking it through, and wanted to just void the comment. But specifically, if the subclass wants to have a different set of constructor arguments than its base class, then presumably the subclass would have to override @@create with that signature. class MyMap extends Map { constructor(a, b, c) { super(); /* other initialization */ } static [Symbol.create](a, b, c) { return super(); } } Is that right? That seems like too much of a burden for the user. And besides, it pollutes the nice separation of responsibilities that we currently have. The current design does posit uninitialized objects, which implementers are obviously uncomfortable with. Could it be that we just haven't yet developed the implementation techniques for dealing with such uninitialized objects? Or is there a real problem with being able to observe them? ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: @@new
On Wed, Jun 18, 2014 at 4:09 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: Jason covered the combinations: his proposal supports class subclassing function, etc. What concretely do you mean here, if not that? If you mean refactoring from one to the other, what observably differs? My understanding of the proposal was that: class F {constructor(x) {this.foo=x}}; turns into the equivalent of: function F(x) { /* ??? the initial message really isn't explicit about what does here */ }; F[Symbol.new] = {[Symbol.new](x) { //use an object literal to create a method kind of function var obj = super(); obj.foo = x }}[Symbol.new].toMethod(F); which is quite different from you get for: function F(x) {this.foo=x}; But again, what user-observable difference are you pointing to? `new F(0)` in either case creates a new object inheriting from F.prototype, sets that object's foo property to 0, and returns that object. Subclassing either one is just `class G extends F {...}`. As a side note, just because you can write something in a complicated way doesn't necessarily mean it's complicated. I think having `F()` and `new F()` do the same thing is simpler for users than having them do different things. Having a single hook for object creation is simpler than having two (like C++) or three (like Ruby and Smalltalk). `function F(x) {this.foo=x}` is short, not simple. -j ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: @@new
On Wed, Jun 18, 2014 at 4:09 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: function F(x) { /* ??? the initial message really isn't explicit about what does here */ }; I think focusing on what was in the initial message vs. what was explained later (or remains open for discussion) does us all a disservice. No proposal springs fully formed from Zeus' head. It's a process. -j ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
```js import * as fs from fs; // importing the named exports as an object import Dict from dict; // importing a default export, same as ever ``` It's a little wordy, but it fulfills the goals and feels pleasant to write. +1 from me. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: @@new
The most important thing here (I agree with Andreas R.) is -- if possible -- avoiding uninitialized object observability. I agree that uninitialized observability is a pain and has been a on-going source of reentrancy bugs in the the more complex built-in constructors. I want to explore whether making the constructor arguments available to @@create provides an alternative way to eliminate that issue. That means depending on the class/built-in a subclass needs to override either the @@create method or the constructor function or both? For example let's take the Map built-in. The @@create method will initialise [[MapData]] to an empty list early on, that way Map instances are never observed uninitialised. Processing the iterable argument to fill the Map may either occur in @@create or in the Map constructor function. Subclasses will need to consult the specification to find out which method needs to be overridden if the iterable argument needs to be preprocessed. For other (more special) built-ins like String/Number/Function/..., @@create will need to perform the complete initialisation including processing the arguments. Otherwise uninitialised objects are still observable. As a result subclasses are required to override @@create and overriding the constructor is a no-op (w.r.t. arguments handling). ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
On Thu, Jun 19, 2014 at 6:41 AM, Calvin Metcalf calvin.metc...@gmail.com wrote: One other option could be for import name from 'path' to resolve to the module body there is no default export, thanks to the static analysis you'll always know when default is present. That is a refactoring hazard. If the module changes to add/remove the default export the import will still succeed but the value is either a module instance object or anything: // a.js export default class C { ... } // importer.js import A from './a'; new A(); Now a.js changes. // a.js V2 export class C { ... } // importer.js import A from './a'; new A(); // TypeError: A is not a function With this idea you cannot look at the import statement to see if the imported binding is a module instance object or not. The import 'path'/this.get syntax is a lot less burdensome if it's only required by edge cases like needing both default export and all the named ones. On Jun 19, 2014 6:32 AM, Michał Gołębiowski m.go...@gmail.com wrote: Thanks, Dave, for bringing that up, it shows you're open for feedback. That said (bikeshed begins), what's wrong with: ```js import fs as fs; ``` ? I feel that a lot of effort went in ES6 into reducing boilerplate via e.g. arrow functions, classes etc. but if you start with Node's require, this adds clutter. Compare these 3 forms of importing all the module lodash bindings to an object _: ```js var _ = require(lodash); // Node import * as _ from lodash; // Dave's syntax import lodash as _; ``` ___ 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 -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
On Jun 19, 2014, at 3:31 AM, Michał Gołębiowski m.go...@gmail.com wrote: Thanks, Dave, for bringing that up, it shows you're open for feedback. That said (bikeshed begins), lol :) what's wrong with: ```js import fs as fs; ``` Indeed we've talked about that one before. Some objected to the inconsistency of having the binding appear at the end and not having the module name at the end (all other import forms have the binding on the left and the module name at the end). But more importantly, this doesn't help with the problem of visually disambiguating from importing the default export. To put it another way, the `*` is critical in the `* as _` syntax, because it makes it explicit that we're talking about the named exports. ? I feel that a lot of effort went in ES6 into reducing boilerplate via e.g. arrow functions, classes etc. but if you start with Node's require, this adds clutter. Compare these 3 forms of importing all the module lodash bindings to an object _: ```js var _ = require(lodash); // Node import * as _ from lodash; // Dave's syntax import lodash as _; ``` My feeling is that the clutter is small, and it's acceptable to have it be slightly less minimal than default export since that is the case we are favoring. This isn't so cluttered as to be downright *punishing* multi-export utility modules (it's literally only two characters longer than your Node code, albeit admittedly a little chattier), but it's good that default import is the winner. Dave ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
With this idea you cannot look at the import statement to see if the imported binding is a module instance object or not. the flip side of that is that you don't need to know whether something is a default export or a named export to import it e.g. ```js export let foo = function () {} export let bar = function () {} ``` and ```js class Baz { foo(){} bar(){} } let baz = new Baz(); export default baz; ``` could both be imported the same. On Thu, Jun 19, 2014 at 9:57 AM, Erik Arvidsson erik.arvids...@gmail.com wrote: On Thu, Jun 19, 2014 at 6:41 AM, Calvin Metcalf calvin.metc...@gmail.com wrote: One other option could be for import name from 'path' to resolve to the module body there is no default export, thanks to the static analysis you'll always know when default is present. That is a refactoring hazard. If the module changes to add/remove the default export the import will still succeed but the value is either a module instance object or anything: // a.js export default class C { ... } // importer.js import A from './a'; new A(); Now a.js changes. // a.js V2 export class C { ... } // importer.js import A from './a'; new A(); // TypeError: A is not a function With this idea you cannot look at the import statement to see if the imported binding is a module instance object or not. The import 'path'/this.get syntax is a lot less burdensome if it's only required by edge cases like needing both default export and all the named ones. On Jun 19, 2014 6:32 AM, Michał Gołębiowski m.go...@gmail.com wrote: Thanks, Dave, for bringing that up, it shows you're open for feedback. That said (bikeshed begins), what's wrong with: ```js import fs as fs; ``` ? I feel that a lot of effort went in ES6 into reducing boilerplate via e.g. arrow functions, classes etc. but if you start with Node's require, this adds clutter. Compare these 3 forms of importing all the module lodash bindings to an object _: ```js var _ = require(lodash); // Node import * as _ from lodash; // Dave's syntax import lodash as _; ``` ___ 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 -- erik -- -Calvin W. Metcalf ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
Sorry to be dense, but I would appreciate more elaboration of this sentence: On Thu, Jun 19, 2014 at 3:40 AM, Axel Rauschmayer a...@rauschma.de wrote: This is a key sentence in David’s proposal: “ES6 favors the single/default export style, What is the single/default export style? If I understand this claim, it says that a module will typically contain a single export statement, either named 'default' or not. Is there any evidence to support this? Everything I've seen contradicts this claim, assuming I understand it. and gives the sweetest syntax to importing the default. Importing named exports can and even should be slightly less concise.” Could you please give an example? In my experience, export default is rare or at least divisive since it seems stylistically incompatible with named exports. On Jun 19, 2014, at 12:31 , Michał Gołębiowski m.go...@gmail.com wrote: Thanks, Dave, for bringing that up, it shows you're open for feedback. That said (bikeshed begins), what's wrong with: ```js import fs as fs; ``` ? I feel that a lot of effort went in ES6 into reducing boilerplate via e.g. arrow functions, classes etc. but if you start with Node's require, this adds clutter. Compare these 3 forms of importing all the module lodash bindings to an object _: ```js var _ = require(lodash); // Node import * as _ from lodash; // Dave's syntax import lodash as _; ``` -- Dr. Axel Rauschmayer a...@rauschma.de rauschma.de ___ 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: ModuleImport
On Thursday, June 19, 2014 5:17 AM, David Herman dher...@mozilla.com wrote: ```js import * as fs from fs; // importing the named exports as an object import Dict from dict; // importing a default export, same as ever ``` My first reaction is to think that a lot of developers will ask: why can't I do `import * from 'fs';`? But it's easier to teach than the alternative. And I agree with the premises: ModuleImport should be there and it should be less convenient than using the default export. Thanks David! Juan ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Duplicate property names (was Re: @@new)
On Wed, Jun 18, 2014 at 12:07 AM, Brendan Eich bren...@mozilla.org wrote: Domenic Denicola wrote: Another way of guiding the decision: I don't quite recall where the spec landed `{ x: 1, [x]: 2 }`, but we should probably be consistent with that. *Mark Miller:* I am ok with removing the constraint that duplicate dynamic object properties throw (in strict mode) with the caveat that we also remove the same constraint for duplicate static properties. from http://esdiscuss.org/notes/2014-06-06#rest-properties- and-spread-properties-sebastian-markb-ge-. https://github.com/rwaldron/tc39-notes/blob/master/es6/2014-06/jun-6.md#conclusionresolution-3 - For both strict and sloppy object literals, both computed and static properties no longer have any duplicate name checking. I would like this the above to be clarified. At the f2f we were talking about spread in object literals. var a = {x: 1, y: 2}; var b = {x: 3, ...a}; However, reading the notes the context is lost and it seems like we are suggestion removing the duplicate property check added in ES5 for strict mode. -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
On Thu, Jun 19, 2014 at 1:15 AM, David Herman dher...@mozilla.com wrote: ## Proposal OK, so we're talking about a better syntax for importing a module and binding its named exports to a variable (as distinct from importing a module and binding its default export to a variable). Here's my proposal: ```js import * as fs from fs; // importing the named exports as an object import Dict from dict; // importing a default export, same as ever ``` Two other possibilities: 1) Only allow export default or named exports, not both. The reason default export is used in module systems today is because there is just one thing that wants to be exported, and it does not matter what its name is because it is indicated by the module ID. Sometimes it is also easier to just use an object literal syntax for the export than expanding that out into individual export statements. Allowing both default and named exports from the same module is providing this syntax/API extension. If there are ancillary capabilities available, a submodule in a package is more likely the way it will be used, accessed as a default export via a module ID like ‘mainModule/sub', instead of wanting to use a default and named export from the same module. It would look like this: import fs from ‘fs’; // only has named exports, so get object holding all the exports import { readFile } from ‘fs’; // only the readFile export import Dict from ‘dict’; // a default export — or — 2) Only allow `export` of one thing from a module, and `import {}` just means allowing getting the first property on that export. This removes the named export checking, but that benefit was always a bit weak, even weaker with the favoring of default export. //d.js, module with a default export, note it does not need a name, //`export` can only appear once in a file. export function() {}; //fs.js, module with “multiple” us export { readFile: function(){} }; //main.js using ‘d’ and ‘fs' import d from ‘d’; import { readFile } from ‘fs’; — Both of those possibilities also fix the disjointed Sytem.import() use with a default export. No need to know that a `.default` is needed to get the usable part. It will match the `import Name from ‘id’` syntax better. James ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
On Thu, Jun 19, 2014 at 6:41 AM, Calvin Metcalf calvin.metc...@gmail.com wrote: One other option could be for import name from 'path' to resolve to the module body there is no default export, thanks to the static analysis you'll always know when default is present. That is a refactoring hazard. If the module changes to add/remove the default export the import will still succeed but the value is either a module instance object or anything: // a.js export default class C { ... } // importer.js import A from './a'; new A(); Now a.js changes. // a.js V2 export class C { ... } // importer.js import A from './a'; new A(); // TypeError: A is not a function With this idea you cannot look at the import statement to see if the imported binding is a module instance object or not. For what it's worth, I have built a sort-of static analysis tool that would give you visibility to these sort of refactoring changes. We currently use it on our code base of around 250 module files that are transpiled on deployment. - es6-import-validate, https://github.com/sproutsocial/es6-import-validate - Also available as a grunt plugin, https://github.com/sproutsocial/grunt-es6-import-validate Jacob ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Duplicate property names (was Re: @@new)
Yes. For both strict and sloppy, for both static/literal and dynamic/computed, duplicate property names/symbols in object literals are no longer an error. Instead, in left-to-right order, each cause the equivalent of a [[DefineOwnProperty]] on the new object, so that rightward definitions silently overwrite conflicting leftward definitions. This should not result in any change to sloppy literals. It just makes strict literals, regarding this issue alone, act like sloppy literals. (Once we have a way to express that a property is to be initialized to a non-configurable state, we'll need to revisit this. But that's after ES6.) Since the object is a new normal object, i.e., not exotic and especially not a proxy, no one should ever be able to observe the object until its initialization is complete. If linters want to warn about statically determined duplicate properties, that is of course their business, and is fine. On Thu, Jun 19, 2014 at 7:47 AM, Erik Arvidsson erik.arvids...@gmail.com wrote: On Wed, Jun 18, 2014 at 12:07 AM, Brendan Eich bren...@mozilla.org wrote: Domenic Denicola wrote: Another way of guiding the decision: I don't quite recall where the spec landed `{ x: 1, [x]: 2 }`, but we should probably be consistent with that. *Mark Miller:* I am ok with removing the constraint that duplicate dynamic object properties throw (in strict mode) with the caveat that we also remove the same constraint for duplicate static properties. from http://esdiscuss.org/notes/2014-06-06#rest-properties- and-spread-properties-sebastian-markb-ge-. https://github.com/rwaldron/tc39-notes/blob/master/es6/2014-06/jun-6.md#conclusionresolution-3 - For both strict and sloppy object literals, both computed and static properties no longer have any duplicate name checking. I would like this the above to be clarified. At the f2f we were talking about spread in object literals. var a = {x: 1, y: 2}; var b = {x: 3, ...a}; However, reading the notes the context is lost and it seems like we are suggestion removing the duplicate property check added in ES5 for strict mode. -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Duplicate property names (was Re: @@new)
Regarding Domenic's question: Domenic Denicola wrote: Another way of guiding the decision: I don't quite recall where the spec landed `{ x: 1, [x]: 2 }`, but we should probably be consistent with that. The initial value of the x property would be 2. It should not be observable that it was 1 at an intermediate stage of the initialization. -- Cheers, --MarkM ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: Standard builtins' prototypes and toString
Can i bring back the good old JScript unknown? :P Sent from my Windows Phone From: Brendan Eich Sent: 6/18/2014 17:15 To: Allen Wirfs-Brock Cc: Mark S. Miller; Mark Miller; Erik Arvidsson; Jason Orendorff; es-discuss@mozilla.org list Subject: Re: Standard builtins' prototypes and toString Allen Wirfs-Brock wrote: [ object ???] [object WTF] :-P /be ___ 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: ModuleImport
On Thu, Jun 19, 2014 at 7:13 AM, Calvin Metcalf calvin.metc...@gmail.com wrote: With this idea you cannot look at the import statement to see if the imported binding is a module instance object or not. the flip side of that is that you don't need to know whether something is a default export or a named export to import it e.g. and elsewhere James Burke wrote: 1) Only allow export default or named exports, not both. I wrote about both of these issues here the other day: https://blog.toshokelectric.com/too-little-too-late-my-thoughts-on-es6-modules/ IMO you can't really implement Calvin's suggestion without making default+named exports an early error, since you don't know where the bindings should come from if a module contains both. This would be great from the perspective of decoupling import/export syntaxes. But mutable bindings gum up the works, in that they provide another avenue for anti-refactoring pressure to flow from module consumer to module author, and the proposed syntax changes here (not by David) as well as in my post would make their behavior even more of a hazard. The syntaxes need to remain coupled in some form because you really *do* want to know if you're getting a mutable binding or not. David's `import * as foo from 'foo'` proposal gets us close enough to the ideal of what's possible now, that it's definitely a +1 here. ES6 favors the single/default export style, and gives the sweetest syntax to importing the default Coupling in action :/ ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
On Thu, Jun 19, 2014 at 6:57 AM, Erik Arvidsson erik.arvids...@gmail.com wrote: On Thu, Jun 19, 2014 at 6:41 AM, Calvin Metcalf calvin.metc...@gmail.com wrote: One other option could be for import name from 'path' to resolve to the module body there is no default export, thanks to the static analysis you'll always know when default is present. That is a refactoring hazard. If the module changes to add/remove the default export the import will still succeed but the value is either a module instance object or anything: // a.js export default class C { ... } // importer.js import A from './a'; new A(); Now a.js changes. // a.js V2 export class C { ... } // importer.js import A from './a'; new A(); // TypeError: A is not a function With this idea you cannot look at the import statement to see if the imported binding is a module instance object or not. I think you're example misses one point - The module author changed the exported api, going from exporting a function named C to exporting an object with a property named C. Problems caused by this refactoring would exist regardless of Calvin's suggestion. Calvin's suggestion would allow the following refactoring to be done by the module author without impacting his users, something not possible with current ES6: ```js // a.js V1 export default { C: class C { ... } } // a.js V2 export class C { ... } ``` The refactoring hazard is real, but exists iff the module consumer uses implicit exports (i.e. an Object.prototype method with the above default export). This is another reason why the named export form is better - everything is explicit. IMO the only good reason to use default export is to export a single function. -chris ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Standard builtins' prototypes and toString
On Jun 19, 2014, at 3:18 AM, Till Schneidereit wrote: On Thu, Jun 19, 2014 at 1:39 AM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: On Jun 18, 2014, at 4:12 PM, Brendan Eich wrote: Allen Wirfs-Brock wrote: The spec. current says throw for this Symbol.prototype case. The (reasonable) opposing view is that toString should never throw. Other than the protoype-is-not-an-instance it all about unlikely edge cases where toString methods are applied to the wrong kind of object. js Object.create(null).toString() typein:1:0 TypeError: Object.create(...).toString is not a function It happens. Better to catch that error (Symbol.prototype flowing into an implicit conversion) early? which is pretty much the approach the ES6 spec. has taken WRT toString up to now. Tension between catching invalid iplicit toString conversions and reliable toString for debugging. I'd posit that there are three different cases for toString: 1) (explictly or implicitly) calling foo.toString, where `foo` is any of the objects that, by default, exist in a JS global without any user code having run 2) (explicitly or implicitly) calling foo.toString, where `foo` is some content script-generated object 3) explicitly calling bar.toString.call(foo), where `foo` and `bar` are arbitrary objects The current (ES5) state of things is that 1) can never throw, while both 2) and 3) might. The current ES6 draft would move 1) over into the latter camp. I think *that* is the crucial thing to prevent. It's just wrong for the language to essentially say here's a bunch of objects. They have methods. But don't call all of them. Finding out which ones aren't allowed to be called is left as an excercise to the reader. Theoretically, Scott's #d still hold the most appeal to me. However, I don't think it works in a multi-Realm world, hence theoretically. Given that, it's #b or #c, where, again, I don't much care which one it'll be. Or even in a single Realm world, it isn't clear how: (class extends Date {}).prototype.toString() would recognize that is is dealing with a prototype rather than a Date instance. I basically agree with you conclusion. An the conserve thing to do is to try to minimize legacy compat. To me, that says that for Date, Number, Boolean, String, RegExp we should do (c). For new kinds of objects that don't exist in ES5 and which have internal state dependent toStrings we should do (b). I'll update the spec. accordingly. Note that for the (c) cases this introduces a different breaking change: ES5 specifies that String.prototype.toString.call({}) throws a TypeError but the (c) based change will return the empty string for that case. Hopefully, that is a change the web can live with. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Standard builtins' prototypes and toString
While we're on the topic, shall we discuss `valueOf()`? Should it get the same treatment? --scott On Jun 19, 2014 1:28 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: On Jun 19, 2014, at 3:18 AM, Till Schneidereit wrote: On Thu, Jun 19, 2014 at 1:39 AM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: On Jun 18, 2014, at 4:12 PM, Brendan Eich wrote: Allen Wirfs-Brock wrote: The spec. current says throw for this Symbol.prototype case. The (reasonable) opposing view is that toString should never throw. Other than the protoype-is-not-an-instance it all about unlikely edge cases where toString methods are applied to the wrong kind of object. js Object.create(null).toString() typein:1:0 TypeError: Object.create(...).toString is not a function It happens. Better to catch that error (Symbol.prototype flowing into an implicit conversion) early? which is pretty much the approach the ES6 spec. has taken WRT toString up to now. Tension between catching invalid iplicit toString conversions and reliable toString for debugging. I'd posit that there are three different cases for toString: 1) (explictly or implicitly) calling foo.toString, where `foo` is any of the objects that, by default, exist in a JS global without any user code having run 2) (explicitly or implicitly) calling foo.toString, where `foo` is some content script-generated object 3) explicitly calling bar.toString.call(foo), where `foo` and `bar` are arbitrary objects The current (ES5) state of things is that 1) can never throw, while both 2) and 3) might. The current ES6 draft would move 1) over into the latter camp. I think *that* is the crucial thing to prevent. It's just wrong for the language to essentially say here's a bunch of objects. They have methods. But don't call all of them. Finding out which ones aren't allowed to be called is left as an excercise to the reader. Theoretically, Scott's #d still hold the most appeal to me. However, I don't think it works in a multi-Realm world, hence theoretically. Given that, it's #b or #c, where, again, I don't much care which one it'll be. Or even in a single Realm world, it isn't clear how: (class extends Date {}).prototype.toString() would recognize that is is dealing with a prototype rather than a Date instance. I basically agree with you conclusion. An the conserve thing to do is to try to minimize legacy compat. To me, that says that for Date, Number, Boolean, String, RegExp we should do (c). For new kinds of objects that don't exist in ES5 and which have internal state dependent toStrings we should do (b). I'll update the spec. accordingly. Note that for the (c) cases this introduces a different breaking change: ES5 specifies that String.prototype.toString.call({}) throws a TypeError but the (c) based change will return the empty string for that case. Hopefully, that is a change the web can live with. Allen ___ 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: ModuleImport
On Jun 19, 2014, at 16:17 , John Barton johnjbar...@google.com wrote: Sorry to be dense, but I would appreciate more elaboration of this sentence: On Thu, Jun 19, 2014 at 3:40 AM, Axel Rauschmayer a...@rauschma.de wrote: This is a key sentence in David’s proposal: “ES6 favors the single/default export style, What is the single/default export style? If I understand this claim, it says that a module will typically contain a single export statement, either named 'default' or not. Is there any evidence to support this? Everything I've seen contradicts this claim, assuming I understand it. The syntax is ( https://people.mozilla.org/~jorendorff/es6-draft.html#sec-exports ): export default AssignmentExpression and gives the sweetest syntax to importing the default. Importing named exports can and even should be slightly less concise.” Could you please give an example? In my experience, export default is rare or at least divisive since it seems stylistically incompatible with named exports. I’m surprised, too. But that seems to be the feedback from people working with large module-based client-side projects and from the Node.js community: single exports are most common. I think in client-side projects, one class per module was reported as a frequent use case: ```js // MyClass.js export default class { ... }; // main.js import MyClass from MyClass; ``` -- Dr. Axel Rauschmayer a...@rauschma.de rauschma.de ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
What if the `import module/id;` form was an expression that evaluated to the module instance object. This means everything stays as it is now except we remove the ModuleImport form and if you want to use the module instance object you can do: `var foo = import foo;`. You could also do `var { bar } = import foo;` - Matthew Robb On Thu, Jun 19, 2014 at 10:48 AM, Axel Rauschmayer a...@rauschma.de wrote: On Jun 19, 2014, at 16:17 , John Barton johnjbar...@google.com wrote: Sorry to be dense, but I would appreciate more elaboration of this sentence: On Thu, Jun 19, 2014 at 3:40 AM, Axel Rauschmayer a...@rauschma.de wrote: This is a key sentence in David’s proposal: “ES6 favors the single/default export style, What is the single/default export style? If I understand this claim, it says that a module will typically contain a single export statement, either named 'default' or not. Is there any evidence to support this? Everything I've seen contradicts this claim, assuming I understand it. The syntax is ( https://people.mozilla.org/~jorendorff/es6-draft.html#sec-exports ): export default AssignmentExpression and gives the sweetest syntax to importing the default. Importing named exports can and even should be slightly less concise.” Could you please give an example? In my experience, export default is rare or at least divisive since it seems stylistically incompatible with named exports. I’m surprised, too. But that seems to be the feedback from people working with large module-based client-side projects and from the Node.js community: single exports are most common. I think in client-side projects, one class per module was reported as a frequent use case: ```js // MyClass.js export default class { ... }; // main.js import MyClass from MyClass; ``` -- Dr. Axel Rauschmayer a...@rauschma.de rauschma.de ___ 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: Standard builtins' prototypes and toString
On Thu, Jun 19, 2014 at 7:46 PM, C. Scott Ananian ecmascr...@cscott.net wrote: While we're on the topic, shall we discuss `valueOf()`? Should it get the same treatment? --scott Oh, yes: I always considered the `toString` discussion to really be about `valueOf`, too. On Jun 19, 2014 1:28 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: On Jun 19, 2014, at 3:18 AM, Till Schneidereit wrote: On Thu, Jun 19, 2014 at 1:39 AM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: On Jun 18, 2014, at 4:12 PM, Brendan Eich wrote: Allen Wirfs-Brock wrote: The spec. current says throw for this Symbol.prototype case. The (reasonable) opposing view is that toString should never throw. Other than the protoype-is-not-an-instance it all about unlikely edge cases where toString methods are applied to the wrong kind of object. js Object.create(null).toString() typein:1:0 TypeError: Object.create(...).toString is not a function It happens. Better to catch that error (Symbol.prototype flowing into an implicit conversion) early? which is pretty much the approach the ES6 spec. has taken WRT toString up to now. Tension between catching invalid iplicit toString conversions and reliable toString for debugging. I'd posit that there are three different cases for toString: 1) (explictly or implicitly) calling foo.toString, where `foo` is any of the objects that, by default, exist in a JS global without any user code having run 2) (explicitly or implicitly) calling foo.toString, where `foo` is some content script-generated object 3) explicitly calling bar.toString.call(foo), where `foo` and `bar` are arbitrary objects The current (ES5) state of things is that 1) can never throw, while both 2) and 3) might. The current ES6 draft would move 1) over into the latter camp. I think *that* is the crucial thing to prevent. It's just wrong for the language to essentially say here's a bunch of objects. They have methods. But don't call all of them. Finding out which ones aren't allowed to be called is left as an excercise to the reader. Theoretically, Scott's #d still hold the most appeal to me. However, I don't think it works in a multi-Realm world, hence theoretically. Given that, it's #b or #c, where, again, I don't much care which one it'll be. Or even in a single Realm world, it isn't clear how: (class extends Date {}).prototype.toString() would recognize that is is dealing with a prototype rather than a Date instance. I basically agree with you conclusion. An the conserve thing to do is to try to minimize legacy compat. To me, that says that for Date, Number, Boolean, String, RegExp we should do (c). For new kinds of objects that don't exist in ES5 and which have internal state dependent toStrings we should do (b). I'll update the spec. accordingly. Note that for the (c) cases this introduces a different breaking change: ES5 specifies that String.prototype.toString.call({}) throws a TypeError but the (c) based change will return the empty string for that case. Hopefully, that is a change the web can live with. Same for Date.prototype.toString({}) as mentioned above, yes. I'm cautiously optimistic about these changes. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
On Thu, Jun 19, 2014 at 1:23 PM, Chris Toshok tos...@gmail.com wrote: On Thu, Jun 19, 2014 at 6:57 AM, Erik Arvidsson erik.arvids...@gmail.com wrote: On Thu, Jun 19, 2014 at 6:41 AM, Calvin Metcalf calvin.metc...@gmail.com wrote: One other option could be for import name from 'path' to resolve to the module body there is no default export, thanks to the static analysis you'll always know when default is present. That is a refactoring hazard. If the module changes to add/remove the default export the import will still succeed but the value is either a module instance object or anything: // a.js export default class C { ... } // importer.js import A from './a'; new A(); Now a.js changes. // a.js V2 export class C { ... } // importer.js import A from './a'; new A(); // TypeError: A is not a function With this idea you cannot look at the import statement to see if the imported binding is a module instance object or not. I think you're example misses one point - The module author changed the exported api, going from exporting a function named C to exporting an object with a property named C. Problems caused by this refactoring would exist regardless of Calvin's suggestion. With the current spec this is a compile time error since a.js (V2) does not export default. Calvin's suggestion would allow the following refactoring to be done by the module author without impacting his users, something not possible with current ES6: ```js // a.js V1 export default { C: class C { ... } } But this is the thing we are trying hard to have people never do. // a.js V2 export class C { ... } ``` The refactoring hazard is real, but exists iff the module consumer uses implicit exports (i.e. an Object.prototype method with the above default export). This is another reason why the named export form is better - everything is explicit. IMO the only good reason to use default export is to export a single function. -chris -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
On Thu, Jun 19, 2014 at 10:53 AM, Matthew Robb matthewwr...@gmail.com wrote: What if the `import module/id;` form was an expression that evaluated to the module instance object. This means everything stays as it is now except we remove the ModuleImport form and if you want to use the module instance object you can do: `var foo = import foo;`. You could also do `var { bar } = import foo;` This is essentially identical to System.get(foo), other than the restriction on the argument being a string. It lends itself to imperative code when what you're after is a declarative syntax. Making it an expression also means it's not a toplevel form in the grammar, and so you could do things like this: function foo() { if (someCondition) return import module1; else return import module2; } or even similar to your examples: var { bar } = someCondition ? import foo : import bar; which would make precise and static computation of the set of imports impossible, and likely complicate module resolution as well. -c ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: @@new
Kevin Smith wrote: The current design does posit uninitialized objects, which implementers are obviously uncomfortable with. Could it be that we just haven't yet developed the implementation techniques for dealing with such uninitialized objects? Or is there a real problem with being able to observe them? André replied well, but I just wanted to confirm: this is not some shallow whiny-implementor-knee-jerk-reaction problem. It's a real problem, for JS programmers as well as implementors. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Standard builtins' prototypes and toString
On Jun 19, 2014, at 10:46 AM, C. Scott Ananian wrote: While we're on the topic, shall we discuss `valueOf()`? Should it get the same treatment? --scott I don't think so. To me, toString is a special case because it is explicitly applied so often, particularly for debugging purposes. But valueOf is primarily invoked for implicit conversions in expressions. Like I described earlier in this thread, TC39's assumption when it agreed to this ES design change was that the web did not generally depend upon using these existing ES3 generation (or earlier) prototypes as instance objects. In the case where we know that wasn't true (Function.prototype) we intentionally did not change the prototype to being a non-instance object. We also agreed if we discovered other such dependencies we would change those prototypes back to being instance objects. Discovering that one of these prototypes objects were being routinely used in expression contexts where valueOf was being implicitly applied would be evidence that that prototype needed to be handled in the legacy manner. But, we don't have any new evidence of that being the case. Until there is some evidence, there isn't any reason to second guess the original analysis and TC39's decision. Allen ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
On Thu, Jun 19, 2014 at 11:06 AM, Erik Arvidsson erik.arvids...@gmail.com wrote: On Thu, Jun 19, 2014 at 1:23 PM, Chris Toshok tos...@gmail.com wrote: On Thu, Jun 19, 2014 at 6:57 AM, Erik Arvidsson erik.arvids...@gmail.com wrote: On Thu, Jun 19, 2014 at 6:41 AM, Calvin Metcalf calvin.metc...@gmail.com wrote: One other option could be for import name from 'path' to resolve to the module body there is no default export, thanks to the static analysis you'll always know when default is present. That is a refactoring hazard. If the module changes to add/remove the default export the import will still succeed but the value is either a module instance object or anything: // a.js export default class C { ... } // importer.js import A from './a'; new A(); Now a.js changes. // a.js V2 export class C { ... } // importer.js import A from './a'; new A(); // TypeError: A is not a function With this idea you cannot look at the import statement to see if the imported binding is a module instance object or not. I think you're example misses one point - The module author changed the exported api, going from exporting a function named C to exporting an object with a property named C. Problems caused by this refactoring would exist regardless of Calvin's suggestion. With the current spec this is a compile time error since a.js (V2) does not export default. Correct, but: ```js // a.js export default class C { ... } // a.js V2 export default { C: class C { ... } } ``` The author changed the shape of the api here as well, preserving default export. Hazards abound once you have an importer. That's what I meant by problems caused by that sort of refactoring existing regardless of Calvin's suggestion - if the shape changes there's nothing you can do in the general case. By adopting something like Calvin's suggestion we can remove a possible module-side hazard, caused by the fact that the shape of an api artificially differs between default export and named exports. Calvin's suggestion would allow the following refactoring to be done by the module author without impacting his users, something not possible with current ES6: ```js // a.js V1 export default { C: class C { ... } } But this is the thing we are trying hard to have people never do. What exactly is it we're trying to have people do? never export more than 1 thing? or never export an object literal, instead favoring Object.create(null, { })? -chris // a.js V2 export class C { ... } ``` The refactoring hazard is real, but exists iff the module consumer uses implicit exports (i.e. an Object.prototype method with the above default export). This is another reason why the named export form is better - everything is explicit. IMO the only good reason to use default export is to export a single function. -chris -- erik ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
On Thu, Jun 19, 2014 at 2:29 PM, Chris Toshok tos...@gmail.com wrote: Calvin's suggestion would allow the following refactoring to be done by the module author without impacting his users, something not possible with current ES6: ```js // a.js V1 export default { C: class C { ... } } But this is the thing we are trying hard to have people never do. What exactly is it we're trying to have people do? never export more than 1 thing? or never export an object literal, instead favoring Object.create(null, { })? If people want to export a bunch of distinct things, each of which should be addressed under a separate name, they should use named exports. If they want to export a single abstraction, then they should use default export. If they want to use both, then they should do both. But if they want to export a bunch of named things, they don't need to use default export for that. Sam ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: @@new
From a security perspective as well, I have always been uncomfortable with observable uninitialized objects, though I have been too lazy to try demonstrating a concrete attack. On Jun 19, 2014 11:12 AM, Brendan Eich bren...@mozilla.org wrote: Kevin Smith wrote: The current design does posit uninitialized objects, which implementers are obviously uncomfortable with. Could it be that we just haven't yet developed the implementation techniques for dealing with such uninitialized objects? Or is there a real problem with being able to observe them? André replied well, but I just wanted to confirm: this is not some shallow whiny-implementor-knee-jerk-reaction problem. It's a real problem, for JS programmers as well as implementors. /be ___ 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: ModuleImport
On Jun 19, 2014, at 13:36 , Michał Gołębiowski m.go...@gmail.com wrote: On Thu, Jun 19, 2014 at 12:40 PM, Axel Rauschmayer a...@rauschma.de wrote: This is a key sentence in David’s proposal: “ES6 favors the single/default export style, and gives the sweetest syntax to importing the default. Importing named exports can and even should be slightly less concise.” There are a lot of large modules that will not disappear overnight. I assume ES6's recommendation for such things (Node's fs module, Lo-Dash) is to make those container objects default exports? What are you saying? That you find this syntax too verbose? ```js import * as fs from fs; ``` There is a little more clutter, but it’s only 2 characters longer than: ```js var fs = require('fs'); ``` This design decision does make sense if single-export modules are indeed much more common. It’s not what I expected, but it does seem to be the case. -- Dr. Axel Rauschmayer a...@rauschma.de rauschma.de ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
On Thu, Jun 19, 2014 at 10:48 AM, Axel Rauschmayer a...@rauschma.de wrote: On Jun 19, 2014, at 16:17 , John Barton johnjbar...@google.com wrote: Sorry to be dense, but I would appreciate more elaboration of this sentence: On Thu, Jun 19, 2014 at 3:40 AM, Axel Rauschmayer a...@rauschma.de wrote: This is a key sentence in David’s proposal: “ES6 favors the single/default export style, What is the single/default export style? If I understand this claim, it says that a module will typically contain a single export statement, either named 'default' or not. Is there any evidence to support this? Everything I've seen contradicts this claim, assuming I understand it. The syntax is ( https://people.mozilla.org/~jorendorff/es6-draft.html#sec-exports ): export default AssignmentExpression Yes, but I was not clear: where is the evidence that ES6 favors this form or single named export. My experience is opposite: the simple thing in ES6 is to export those things you want exported. If it's one thing, then one; if it's 6 things then 6. One is not favored. and gives the sweetest syntax to importing the default. Importing named exports can and even should be slightly less concise.” Could you please give an example? In my experience, export default is rare or at least divisive since it seems stylistically incompatible with named exports. I’m surprised, too. But that seems to be the feedback from people working with large module-based client-side projects and from the Node.js community: single exports are most common. I still don't get it. If you want one export, just export one thing. If you want one big export object called _, then export var _ = {tons of stuffs} One of the best references for devs to understand modules: http://www.2ality.com/2013/07/es6-modules.html says: The syntax for importing a default export is similar to normal importing, but there are no braces To me this is a bug not a feature; we should keep it simple and just have one way to get one import from one export. Just to make a connection to the topic, Dave's intro says: We've consistently seen confusion between the semantics of ModuleImport and default export. For me this confusion lands on default export equally as 'module` import. I think in client-side projects, one class per module was reported as a frequent use case: ```js // MyClass.js export default class { ... }; // main.js import MyClass from MyClass; ``` -- Dr. Axel Rauschmayer a...@rauschma.de rauschma.de ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: ModuleImport
From: es-discuss es-discuss-boun...@mozilla.org on behalf of David Herman dher...@mozilla.com * **Without ModuleImport, authors of multi-export modules would be pressured to circumvent the named exports functionality.** I am glad this point was recognized and acted upon. I feel listened-to :) * **The syntax should still favor default import.** Glad that this piece of (strong, pervasive) community feedback is still being kept at the forefront, despite continual naysaying and disbelief from various quarters. I do acknowledge the concerns about reopening topics for debate and delay. [...] But keep in mind it doesn't matter what spec it lands in as long as implementations are shipping it. This is part of a larger issue regarding the messaging of TC39 and versioned ECMAScript, which is somewhat out of touch with [reality](https://twitter.com/annevk/status/479334108150374401). I hope we can discuss this at the next TC39 meeting. But I don't mean to derail the thread. ```js import * as fs from fs; // importing the named exports as an object ``` This looks great. Other alternatives I thought about in response included `import { * } as fs from fs` and `import module fs from fs`, but upon consideration the brevity of yours wins. I just hope we can do better documenting it, this time around, and fixing the many transpilers with their confusing semantics. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
To me this is a bug not a feature; we should keep it simple and just have one way to get one import from one export. Just to make a connection to the topic, Dave's intro says: We've consistently seen confusion between the semantics of ModuleImport and default export. For me this confusion lands on default export equally as 'module` import. Personally, I agree, but many people feel strongly about the single-export use case. If default exports help with getting ES6 modules adopted more broadly then the slight increase in complexity is worth it. Let’s compare. Your approach – slightly more redundant: ```js // MyClass.js export class MyClass { ... } // main1.js import { MyClass } from MyClass; // myFunc.js export function myFunc(...) { ... } // main2.js import { myFunc } from myFunc; ``` Default exports: ```js // MyClass.js export default class { ... }; // main1.js import MyClass from MyClass; // myFunc.js export default function (...) { ... }; // main2.js import myFunc from myFunc; ``` -- Dr. Axel Rauschmayer a...@rauschma.de rauschma.de ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: Standard builtins' prototypes and toString
On Thu, Jun 19, 2014 at 8:16 PM, Allen Wirfs-Brock al...@wirfs-brock.com wrote: On Jun 19, 2014, at 10:46 AM, C. Scott Ananian wrote: While we're on the topic, shall we discuss `valueOf()`? Should it get the same treatment? --scott I don't think so. To me, toString is a special case because it is explicitly applied so often, particularly for debugging purposes. But valueOf is primarily invoked for implicit conversions in expressions. Like I described earlier in this thread, TC39's assumption when it agreed to this ES design change was that the web did not generally depend upon using these existing ES3 generation (or earlier) prototypes as instance objects. In the case where we know that wasn't true (Function.prototype) we intentionally did not change the prototype to being a non-instance object. We also agreed if we discovered other such dependencies we would change those prototypes back to being instance objects. Discovering that one of these prototypes objects were being routinely used in expression contexts where valueOf was being implicitly applied would be evidence that that prototype needed to be handled in the legacy manner. But, we don't have any new evidence of that being the case. Until there is some evidence, there isn't any reason to second guess the original analysis and TC39's decision. Ok, we'll try this in Nightly for Date.prototype and see if the assumption holds. If it does, we'll continue with the rest. I don't really know if Date.prototype is a good canary, but it's what I have a mostly-finished patch for, and it doesn't seem to make too much of a difference. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: ModuleImport
From: es-discuss es-discuss-boun...@mozilla.org on behalf of James Burke jrbu...@gmail.com 1) Only allow export default or named exports, not both. As a modification of the current design, this hurts use cases like ```js import glob, { sync as syncGlob } from glob; import _, { zip } from underscore; ``` 2) Only allow `export` of one thing from a module, and `import {}` just means allowing getting the first property on that export. This removes the named export checking, but that benefit was always a bit weak, even weaker with the favoring of default export. I definitely believe that if the community were designing a syntax-based module format, incorporating the lessons learned so far, it would end up being along these lines. We've learned enough from browserify and RequireJS's CommonJS-wrapping to know that a top-level static import form has serious benefits, but we've also learned that `module.exports =` or `return` are the recommended and primary pattern, and you can always attach things to that default export as properties if necessary. (In CommonJS terms, we've learned that the benefits of typing `exports.x = y` instead of `module.exports.x = y` are not great enough to outweigh the minor confusion of having two export forms.) Unfortunately, that's not the world we live in, and instead TC39 is designing a module system based on their own priorities. (Static checking of multi-export names, mutable bindings, etc.) They've (wisely) decided to add affordances for the community's use cases, such as layering default exports on top of the multi-export model. As well as Dave's proposal in this thread to de-grossify usage of modules like fs. By doing so, they increase their chances of the module system being good enough for the community, so that the path of least resistance will be to adopt it, despite it not being designed for them primarily. It's still an open question whether this will be enough to win over the community from their existing tools, but with Dave's suggestion I think it has a better-than-even chance. The transitional era will be a particularly vulnerable time for TC39's module design, however: as long as people are using transpilers, there's an opportunity for a particularly well-crafted, documented, and supported transpiler to give alternate semantics grounded in the community's preferred model, and win over enough of an audience to bleed the life out of TC39's modules. We already see signs of community interest in such ES6+ transpilers, as Angular illustrates. Even a transpiler that maintains a subset of ES6 syntax would work: if it supported only `export default x`, and then gave `import { x } from y` destructuring semantics instead of named-binding-import semantics, that would do the trick. Interesting times. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: @@new
On Thu, Jun 19, 2014 at 8:39 AM, André Bargull andre.barg...@udo.edu wrote: That means depending on the class/built-in a subclass needs to override either the @@create method or the constructor function or both? For example let's take the Map built-in. The @@create method will initialise [[MapData]] to an empty list early on, that way Map instances are never observed uninitialised. Processing the iterable argument to fill the Map may either occur in @@create or in the Map constructor function. Right. It should happen in the constructor. Map[@@create] can ignore its arguments and return an empty Map. Subclasses will not need to override @@create. Subclasses will need to consult the specification to find out which method needs to be overridden if the iterable argument needs to be preprocessed. Or just try it and see what happens, which is what people seem to do in practice. For Map, everything would just work. However, TC39 could not then evolve Map[@@create] to take arguments in a later edition. Existing subclasses would rely on Map[@@create] ignoring its arguments. For other (more special) built-ins like String/Number/Function/..., @@create will need to perform the complete initialisation including processing the arguments. Otherwise uninitialised objects are still observable. As a result subclasses are required to override @@create and overriding the constructor is a no-op (w.r.t. arguments handling). All correct. :-| For a time yesterday, I hoped that @@create + constructor would solve everything. Classes that need to fully initialize would use @@create; all other code would use constructor; nobody would have to care which. But Kevin's right: subclasses would need to care, and it's a burden. -j ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
All good points. I don’t see “TC39 versus the community”, though, I’m seeing many factions with different opinions. On Jun 19, 2014, at 21:13 , Domenic Denicola dome...@domenicdenicola.com wrote: From: es-discuss es-discuss-boun...@mozilla.org on behalf of James Burke jrbu...@gmail.com 1) Only allow export default or named exports, not both. As a modification of the current design, this hurts use cases like ```js import glob, { sync as syncGlob } from glob; import _, { zip } from underscore; ``` 2) Only allow `export` of one thing from a module, and `import {}` just means allowing getting the first property on that export. This removes the named export checking, but that benefit was always a bit weak, even weaker with the favoring of default export. I definitely believe that if the community were designing a syntax-based module format, incorporating the lessons learned so far, it would end up being along these lines. We've learned enough from browserify and RequireJS's CommonJS-wrapping to know that a top-level static import form has serious benefits, but we've also learned that `module.exports =` or `return` are the recommended and primary pattern, and you can always attach things to that default export as properties if necessary. (In CommonJS terms, we've learned that the benefits of typing `exports.x = y` instead of `module.exports.x = y` are not great enough to outweigh the minor confusion of having two export forms.) Unfortunately, that's not the world we live in, and instead TC39 is designing a module system based on their own priorities. (Static checking of multi-export names, mutable bindings, etc.) They've (wisely) decided to add affordances for the community's use cases, such as layering default exports on top of the multi-export model. As well as Dave's proposal in this thread to de-grossify usage of modules like fs. By doing so, they increase their chances of the module system being good enough for the community, so that the path of least resistance will be to adopt it, despite it not being designed for them primarily. It's still an open question whether this will be enough to win over the community from their existing tools, but with Dave's suggestion I think it has a better-than-even chance. The transitional era will be a particularly vulnerable time for TC39's module design, however: as long as people are using transpilers, there's an opportunity for a particularly well-crafted, documented, and supported transpiler to give alternate semantics grounded in the community's preferred model, and win over enough of an audience to bleed the life out of TC39's modules. We already see signs of community interest in such ES6+ transpilers, as Angular illustrates. Even a transpiler that maintains a subset of ES6 syntax would work: if it supported only `export default x`, and then gave `import { x } from y` destructuring semantics instead of named-binding-import semantics, that would do the trick. Interesting times. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss -- Dr. Axel Rauschmayer a...@rauschma.de rauschma.de ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
Yes, but I was not clear: where is the evidence that ES6 favors this form or single named export. My experience is opposite: the simple thing in ES6 is to export those things you want exported. If it's one thing, then one; if it's 6 things then 6. One is not favored. FWIW, my experience (again) agrees with yours. In all the ES6 modular code I've written over the past couple of years, I've never felt a need or a desire to use the default feature. For me, personally, it's a distraction. However, we are where we are, and we need to make progress. I think the current design is something that we can all move forward with, even if we don't agree with every design decision. Put another way, you and I can happily ignore the default feature, and have a bit of a laugh when we see it resulting in confusion ; ) Kevin ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
On Thu, Jun 19, 2014 at 12:13 PM, Domenic Denicola dome...@domenicdenicola.com wrote: From: es-discuss es-discuss-boun...@mozilla.org on behalf of James Burke jrbu...@gmail.com 1) Only allow export default or named exports, not both. As a modification of the current design, this hurts use cases like ```js import glob, { sync as syncGlob } from glob; import _, { zip } from underscore; ``` It is just as likely the module author will specify sync and zip as properties of their respective default export. Particularly since those are coming from JS modules that come from existing module systems. So a destructuring assignment would be needed, following the default import. It works out though, and is not that much more typing. That, or those pieces would be available as ‘underscore/zip’ or ‘glob/sync' imports. The argument for allowing both a default and named exports seems ill-defined based on data points known so far, and by avoiding it, it reduces the number of import forms and aligns better with System.import use. James ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: ModuleImport
From: James Burke [mailto:jrbu...@gmail.com] The argument for allowing both a default and named exports seems ill-defined based on data points known so far I mean, it seems based on the idea that named exports are super-important, and that packages like glob and underscore should use them. I agree that it's unclear whether this will occur, but that seems to be the reasoning. ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
RE: ModuleImport
But why? The benefit of named exports in general is that you get the magic mutable bindings -- but underscore and glob are mature libraries without circular dependencies on other code. They would gain exactly nothing from switching to named exports. --scott On Jun 19, 2014 4:16 PM, Domenic Denicola dome...@domenicdenicola.com wrote: From: James Burke [mailto:jrbu...@gmail.com] The argument for allowing both a default and named exports seems ill-defined based on data points known so far I mean, it seems based on the idea that named exports are super-important, and that packages like glob and underscore should use them. I agree that it's unclear whether this will occur, but that seems to be the reasoning. ___ 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: ModuleImport
Domenic Denicola wrote: This is part of a larger issue regarding the messaging of TC39 and versioned ECMAScript, which is somewhat out of touch with [reality](https://twitter.com/annevk/status/479334108150374401). (Spinach.) I hope we can discuss this at the next TC39 meeting. But I don't mean to derail the thread. Too late. ```js import * as fs from fs; // importing the named exports as an object ``` This looks great. Other alternatives I thought about in response included `import { * } as fs from fs` and `import module fs from fs`, but upon consideration the brevity of yours wins. I just hope we can do better documenting it, this time around, and fixing the many transpilers with their confusing semantics. Finalize the normative spec, see what happens. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss
Re: ModuleImport
Domenic Denicola wrote: The transitional era will be a particularly vulnerable time for TC39's module design, however: as long as people are using transpilers, there's an opportunity for a particularly well-crafted, documented, and supported transpiler to give alternate semantics grounded in the community's preferred model, and win over enough of an audience to bleed the life out of TC39's modules. You're doing a disservice to everyone here by implying that such a transpiler could trump native modules as implemented per the normative ES6 spec in Chakra, JSC, SpiderMonkey, and V8. Idle speculations are not even worth betting on, but filling es-discuss with tendentious idle speculations is worse. Cut it out. /be ___ es-discuss mailing list es-discuss@mozilla.org https://mail.mozilla.org/listinfo/es-discuss