ModuleImport

Isiah Meadows impinball at gmail.com
Sat Jun 28 03:00:33 PDT 2014


(I get the digest...)

First, I will say that you all beat me to my (almost) exact suggestion on
the syntax, @Russell and @Scott.

Second, `module foo from 'foo'` is counterintuitive, confusing,
non-obvious, and really needs trashed IMHO.

Now, to supplement these ideas, I will summarize how I think it may work
best:

// import default export(s)

import 'lo-dash' as _;
import 'fs' as fs;

// import specific named export
// imports as $.extend

import extend in $ from 'jquery';

// import multiple named exports
// imports as _, with members .map and .each

import map, each in _ from 'underscore';

// import members of an export
// imports those members into the module namespace

import map, each from 'underscore';

// import all named exports as properties of _
import * in _ from 'lo-dash';

// import all named exports into module namespace

import * from 'lo-dash';

// import as different name in current module

import reallyReallyLongFunctionName as foo from './foo';

// import as different property name
// likely atypical, would show up as something most wouldn't think
// of a while down the road

import reallyReallyLongFunctionName as func in foo from './foo';

The keyword "in" is used to both note that they are properties in the
module. It is not "as" to limit confusion: "as" is better to dictate names.
The basic syntax grammar could be defined as follows (please pardon my
inability to format...I'm typing this from a phone):

ModuleName:
    "module-path"

ModuleName:
    'module-path'

ImportStatement:
    One of:
        DefaultImportStatement
        NamedImportStatement

DefaultImportStatement:
    import ModuleName as Identifier;

NamedImportStatement:
    import NamedImports from ModuleName;

NamedImports:
    One of:
        NamedIdentifiers
        NamedImport

NamedImport:
    NamedIdentifiers in Identifier

NamedIdentifiers:
    NamedIdentifier , NamedIdentifiers

NamedIdenifiers:
    NamedIdentifier

NamedIdentifier:
    One of:
        Identifier
        Identifier as Identifier

This is my proposed syntax. It is somewhat Pythonic, but slightly more
verbose because file names aren't themselves restricted like identifiers.

Here's a couple more real world examples:

import 'jquery' as $;
$('#button').attr('onClick', () => alert('You clicked the button!'));

// ========================== //

import readdir, stat from 'fs';
import 'path' as path;

function walk(dir, cb) {
  readdir(path.resolve(dir), (error, files) => files.forEach(file => {
    let file = dir + path.sep + file;
    let fileStat = stat(file);
    if (fileStat && fileStat.isDirectory()) {
      walk(file, cb);
    } else {
      cb(file);
    }
  }));
}

Here's the version more popular out of the other suggestions:

import {$} from 'jquery';
$('#button').attr('onClick', () => alert('You clicked the button!'));

// ========================== //

import {readdir, stat} from 'fs';
import path from 'path';

function walk(dir, cb) {
  readdir(path.resolve(dir), (error, files) => files.forEach(file => {
    let file = dir + path.sep + file;
    let fileStat = stat(file);
    if (fileStat && fileStat.isDirectory()) {
      walk(file, cb);
    } else {
      cb(file);
    }
  }));

Which looks better? Which is more obvious and intuitive?

On another note, look at the bright side and compare these with the ES5
equivalents:

define(['jquery'], function ($) {
  $('#button').attr('onClick', function () {
    alert('You clicked the button!');
  });
});

// ========================== //

var fs = require('fs');
var path = require('path');

function walk(dir, cb) {
  fs.readdir(path.resolve(dir), function (error, files) {
    files.forEach(function (file) {
      var file = dir + path.sep + file;
      var stat = fs.stat(file);
      if (stat && stat.isDirectory()) {
        walk(file, cb);
      } else {
        cb(file);
      }
    });
  });
}

I think we've made some relatively good progress so far. That last is just
unnecessarily complicated in syntax.

<aside>
Is it me, or is ECMAScript starting to become Python crossed with a
curly-brace version of Scheme? I'm starting to see a lot of new
functionally oriented syntax and methods being added to ES6 and considered
for ES7, while at the same time Pythonic OOP and reflection being
considered simultaneously. The arrow functions are effectively lambdas that
can be complete functions in their own right.

I wonder how long it will take for people will find out the ease of
currying and more availability of functional techniques in ES6.
var foo = (a, b) => (c) => a * b + c;
var adder = a => b => a + b;
var addOne = adder(1);
var two = addOne(1);
</aside>

> ---------- Forwarded message ----------
> From: Russell Leggett <russell.leggett at gmail.com>
> To: Kevin Smith <zenparsing at gmail.com>
> Cc: es-discuss <es-discuss at mozilla.org>
> Date: Thu, 26 Jun 2014 10:50:20 -0400
> Subject: Re: ModuleImport
>
>>> Now the author can choose to export more things later without making
breaking changes to the module. The only downside to this is the
(apparently mandatory) curly braces around the imported object. If single
export/import becomes the convention with ES6 modules then users will be
forced to type an extra pair of {} several times in most of their files. Is
the two extra characters something we can live with?
>>
>>
>>
>> I have a good bit of experience coding ES modules, and I was worried
about that at first.  But hasn't been a problem for me.  Then again, I'm
just one person - it would be good to get more data from developers
actually coding with ES modules.
>>
>> This syntax would make things completely obvious and simple though:  if
there's curly braces, then you're reaching into the bag and pulling out
things, and if there's no curly braces, you're getting the bag itself.
 There's even a visual analogy at play here:  the curly braces themselves
resemble the sides of a bag.
>>
>
> To me, though, that goes back to the destructuring/not destructuring
aspect. Maybe this has floated by during the bikeshedding, but why not
something like:
>
>     //import a single named export
>     import foo from "bar";
>
>     //import multiple named exports
>     import foo, baz from "bar";
>
>     //alias an imported named export
>     import foo as fooAlias from "bar";
>
>     //import the module
>     import "bar" as bar;
>
> So basically, just get rid of the {} for importing named exports, and
move the whole module import after the as. It reads better to me and I
think is more intuitive. As for default exports - I think they only make
sense if done the way it works in node. A single default export that
effectively replaces the module. Let's remember how it gets used in node:
>
>     var _ = require("underscore");
>
> In node, if they didn't do it as a single export, then you would have to
do:
>
>     var _ = require("underscore")._;
>
> Given that underscore (and jquery and several others) are only a single
export, it would be annoying and error prone to do that all over the place.
The value added was for the importer - *not the exporter*. With the new
syntax I'm proposing, importing underscore would be exactly the same as
what the current proposal is for default export imports.
>
>     import _ from "underscore";
>
> Its just that underscore would have to have the named export _. As I
said, though, that's not really a burden, and the argument for default
exports was never really for the module writer.
>
> There is one small case I'm missing, which is that default export imports
let you name the import whatever you want without writing extra code for
the alias. I don't really find that as a drawback, but then again, I do
write a lot of Java in addition to JavaScript. I don't really see any other
languages that operate this way either, and I would come back again to the
distinct history and constraints that JS/node has had up until now. If keep
that flexibility/matching semantics for smoothest continuity, I would
propose that default exports have to be a *single* default export, and that
it would replace module importing instead of export importing.
>
>     import "underscore" as _;
>
> Where there is a single default export in the underscore module. This
would mean that the normal module import semantics don't work in this case,
but that is the tradeoff decided by the module author. I personally don't
think its worth adding this feature, but if it were added, I would expect
it to work this way.
>
>
> ---------- Forwarded message ----------
> From: "C. Scott Ananian" <ecmascript at cscott.net>
> To: Russell Leggett <russell.leggett at gmail.com>
> Cc: es-discuss <es-discuss at mozilla.org>
> Date: Thu, 26 Jun 2014 11:56:23 -0400
> Subject: Re: ModuleImport
> On Thu, Jun 26, 2014 at 10:50 AM, Russell Leggett <
russell.leggett at gmail.com> wrote:
>>
>> To me, though, that goes back to the destructuring/not destructuring
aspect. Maybe this has floated by during the bikeshedding, but why not
something like:
>>
>>     //import a single named export
>>     import foo from "bar";
>>
>>     //import multiple named exports
>>     import foo, baz from "bar";
>>
>>     //alias an imported named export
>>     import foo as fooAlias from "bar";
>>
>>     //import the module
>>     import "bar" as bar;
>
>
> I like the fact that this doesn't look like destructuring, since variable
binding is different from destructuring assignment.  Could
> ```
> import foo, baz from "bar" as bar;
> ```
> allowed simultanous import of named exports and the module itself?  If
so, the grammar gains a pleasing regularity.
>
> OTOH, I think this syntax reorganization is orthogonal to some of the
other issues discussed.  In particular, your latter proposal still allows
for user confusion between:
> ```
> import _ from "underscore";
> import "underscore" as _;
> ```
> The various proposals seem to try to address this by making these
semantically identical (or near-identical, with some cooperation from the
module author).
>  --scott
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20140628/b9e33198/attachment-0001.html>


More information about the es-discuss mailing list