ES Modules: suggestions for improvement

Claus Reinke claus.reinke at talk21.com
Tue Jul 24 02:03:43 PDT 2012


> On the subject of 'exporting one value', there are a few things to say:
> 
> 1. It's been asserted repeatedly that libraries that export 'just one
> value' are a better design, but while this is excellent style in lots
> of cases, I don't think a persuasive case has been made that this
> should be the *only* style.  Dave listed a number of key Node
> libraries that don't follow this rule, and if you look at other
> libraries or other languages you mostly see the same thing --
> sometimes it's the right thing, and sometimes it isn't.

As Isaac replied, those exceptions are not examples to follow.
As I've tried to point out in my summary, separate exports in ES6
won't be as hard to untangle as separate export assignments in ES5.

Personally, my problem is not so much with different styles, but
with which style is taken as the basis of the export system design.

Compare

    module M {
        .. lots of code ..
        export var x = ..;
        function helper(..) {..}
        export var y = helper(..);
    }

with

    module M {
        .. lots of code ..
        var x = ..;
        function helper(..) {..}
        var y = helper(..);
        export {x,y}    // or, without punning: export {x: x, y: y}
    }

The former is using the harder-to-read style, but the (top level of)
export interface can still be extracted without running the code, so
even with this style, we have an improvement over ES5 modules.

However, the export object is implicit, and local variable names
are directly tied to export object properties. In my experience with
module systems, separating local names from exported/imported
names is important (for preserving the static/dynamic phase
distinction when adding more dynamic features to the design).

The latter variant not just makes it easier for humans to find the 
export interface, which -as you say- is a matter of style. It also
has an explicit export object, and it separates the local names 
from the exported properties. Using property punning (x 
aas a shortcut for "x" : x), we can still have the convenience of 
just listing the exported names but the desugared version 
shows that we have separated local from exported names.

To give just one example of why this is important: imagine a
renaming refactoring applied to this module. In the former
variant (the current spec), renaming a variable that happens
to be exported implies propagating that renaming to all importers!

> 2. Exporting a value *as* the module runs into tricky issues in the
> relationship between the prototype hierarchy, the exports, and the
> definition of module instances.  For example, should exporting a
> function as *the* export of a module named `M` mean that `M.call` is
> also available?

Hm, I hadn't thought about that, but my intuition tells me that
there should be an export object for every module, with just the
exports, and that this export object should be accessible from 
the module object. 

The module object might have other properties, and depending 
on how this is organized (module system properties in the
prototype chain of the export object, or the export object as
component of the module object), the module object itself
might not support 'M.call', but there should be a way to get to
the export object within the module object, and that should
definitely support something like 'M.exports.call' if M's export
is a function.

[splitting my reply here]

To summarize: I have no problem with separate exports as
a convenience on top of an export system that maintains an
explicit export object and separates local from exported names.

I do have a problem with an export system that conflates
local and exported names and does not provide access to
an unmodified export object.

Does this clarify my concerns?
Claus

 


More information about the es-discuss mailing list