> -----Original Message-----

> From: es-discuss [mailto:[email protected]] On Behalf Of

> Sébastien Cevey

> Sent: Friday, June 20, 2014 3:46 AM

> To: Axel Rauschmayer

> Cc: es-discuss list

> Subject: Re: ModuleImport

>

> On 20 June 2014 11:39, Axel Rauschmayer <[email protected]> wrote:

> > > The `*' symbol universally represents a glob of "everything", but

> > > when used to import from a module that has multiple exports, you

> > > won't get everything, you will get either the single default export

> > > (if there is

> > > one) or nothing.

> >

> >

> > What gives you that impression? Quoting David’s original email:

> >

> > ```js

> > import * as fs from "fs"; // importing the named exports as an object

> > import Dict from "dict";  // importing a default export, same as ever

> > ```



With all due respect, why is it that we cannot change the specification to 
allow `import name from "module"` for both the default export (for single 
export modules) and the Module object (for multi-named export modules). The 
same question goes for using `import { name as "name" } from "module"` for 
both. As specified, a default export is equivalent to a Module object with a 
"default" property, and as a result requires special handling with respect to 
how it is bound to the _ImportBinding_ in `import name from "module"`. Wouldn't 
it make sense to simplify the syntax and expand the static and runtime 
semantics for imports? Are we sure that the current semantics are the right 
approach that we should shoehorn the syntax into?



Is it imperative for module authors to be able to provide both a default export 
*and* named exports within the same module? From most of the comments in this 
thread, it seems that expected module use falls into two categories:  
Single-export modules and Multi-export modules. Is there a use-case in the wild 
(via ES6 module transpilers) where a single module today uses both a default 
export as well as named exports?



With respect to Node libraries, I often see one of three approaches to 
exporting from a module:



_Named Exports_:

```

exports.foo = 1;

// or

module.exports.foo = 1;

```



_Single Export Object_:

```

module.exports = {

  foo: 1,

  bar: function() {}
}

```



_Single Export Function_:

```

module.exports = function() { }

```



In Node, if you wanted to have a default export that is a function, but also 
have additional exports you would most likely add them as data properties on 
the function:

```

module.exports = function() {}

module.exports.foo = 1;

```



Given that, why not simplify the syntax and semantics to just the following 
three forms:

```

import "module"; // imports the module but does not perform binding

import name from "module"; // imports the module (either the default export or 
a module object with the named exports, see below)

import { name1, name2 as "otherName" } from "module"; // imports members of the 
module.

```



Simplifying this requires the following (approximate) changes in semantics:



* Either (A) a module cannot have *both* a default export and named exports, 
_or_..

* (B) A modules named exports become attached properties of the default export 
if provided.

    * If (B), it becomes an runtime error to add a default export after a named 
export, and a runtime error to add a named export if the default export is not 
an Object.

* The ImportBinding (`name` above) becomes bound to a [[Value]] property of an 
(not part of the current spec) Import exotic object.

* When the Module exotic object is loaded, if it has a property named 
"default", that becomes the value of the [[Value]] property of the Import 
exotic object.

* If the Module exotic object does not have a property named "default", the 
Module itself becomes the value of the [[Value]] property of the Import exotic 
object.

* NamedImports now points to bindings to the [[Value]] property of the Import 
exotic object. If you want both a default export and named exports, attach the 
named exports as properties of the default export.



With the above changes, whether you're using a default export or named exports 
becomes transparent to the developer.  If the developer _really_ wants the 
module object, they could fall back to:

```

import "module";

var name = System.get("module"); // Returns the Module object without the 
transformations applied from above.

```



The above is a rough approximation of the semantics changes. If anyone finds 
merit to this proposal, I'll find some time this weekend to write out exactly 
what kind of changes there would need to be in the static and runtime semantics 
in the current spec. The overall goal is to keep the import syntax simple and 
expand the static and runtime semantics to support that simplicity. This 
includes continuing to support the ability to handle cyclic dependencies. 
Engine authors will need to write the code for the import semantics once, while 
the development community will use the import syntax over and over for some 
time to come. It seems like a simpler syntax should win out over possibly 
changing the semantics.



Best regards,

Ron









p.s. Here are some examples of various inputs and outputs based on this 
proposal:



# Exports



[named-exports.js]

```

export var version = "1.0";

export function println(text) { console.log(text); }

```



[single-export.js]

```

function hello (text) { alert("Hello " + text + "!"); }

hello.goodbye = function (text) { alert("Goodbye " + text + "!"); }

export default hello;

```



[multi-export-with-default.js]

```

// if (A) above, this is an early error

// if (B) above, version becomes Person.version

export default class Person {

  jump() { return "How high?"; }
}

export var version = "2.0";

```



[single-export-of-object.js]

```

export default {

  version: "1.0",

  assert(test) { if (!test) throw new Error("failed!"); }

}

```



# Imports



[import-named-imports.js]

```

import namedExports from "named-exports"; // namedExports = binding to 
Import.[[Value]] which results in a Module object with properties "version" and 
"println";

import { version, println } from "named-exports"; // version = binding to 
Import.[[Value]].version, println = binding to Import.[[Value]].println

// or...

import namedExports, { version, println } from "named-exports"; // both of the 
above

```



[import-single-export.js]

```

import hello from "single-export"; // hello = binding to Import.[[Value]] which 
results in the "hello" function

import { goodbye } from "single-export"; // goodbye = binding to 
Import.[[Value]].goodbye

// or...

import hello, { goodbye } from "single-export"; // both of the above

```



[import-multi-export-with-default.js]

```

// assumes (B) above

import Person from "multi-export-with-default"; // Person = binding to 
Import.[[Value]] which results in the "Person" class

import { version } from "multi-export-with-default"; // version = binding to 
Import.[[Value]].version

// or...

import Person, { version } from "multi-export-with-default"; // both of the 
above

```



[import-single-export-of-object.js]

```

import test from "single-export-of-object"; // test = binding to 
Import.[[Value]] which results in an Object with properties "version" and 
"assert"

import { version, assert } from "single-export-of-object"; // version = binding 
to Import.[[Value]].version, assert = binding to Import.[[Value]].assert

// or...

import test, { version, assert } from "single-export-of-object"; // both of the 
above.

```




_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to