ES Modules: suggestions for improvement

David Herman dherman at
Sat Jul 21 00:15:27 PDT 2012

On Jul 20, 2012, at 9:23 PM, Isaac Schlueter wrote:

> On Fri, Jun 29, 2012 at 4:33 PM, David Herman <dherman at> wrote:
>>> var fs = require('fs')
>>> // no path here...
>>> function notCoveredByTests () {
>>>"yabbadabba"), ...)
>>> }
>> Right.
>>> How would any of this solve that?
>> Because `path` is unbound, and static variable checking reports that as an error.
> And this works because modules don't share global namespace with one
> another?  (If they do share global space, then how would the static
> checker know that it won't be assigned to a global 'path' by that
> time?)

They do share a global namespace, and the static checker doesn't know that a new global won't be assigned. It's an early error to refer to a variable that doesn't exist at the time of checking.

>> But we should not force this style on programmers.
> It's not forcing anything on programmers.
> If you want to export a bag of functions, then put the functions on an
> object, and export the object.
> It *is* making it trickier to figure out how to add types and macros,
> but I'm less excited about those features than I am about making our
> existing problems easier to solve.

It's not trickier, it's essentially impossible. If we don't support static imports and exports, those doors are shut. Not to mention the other things I mentioned in my blog post, including straightforward optimizations and interoperability with modules written in other languages.

>> Even Node itself does not adhere strictly to that style -- look at the 'path' or 'fs' libraries, for example.
> I consider that a mistake.  And even there, there's a single "exports"
> object that methods are assigned to.

I'm still having a hard time telling whether your "just one export" thing descends into tautology. I mean, clearly a set of n things can be thought of either as n things or 1 set. But does that actually tell us anything?

>> Same with the ES standard library: Math and JSON are both multi-export (pseudo-)modules that just export functions.
> They export a single object that has functions attached to it.
> Math.pow(), JSON.parse, etc.
> export { parse: parse, stringify:stringify }

Again, this is obvious, so I'm not sure what you're demonstrating. Clearly if we don't care about any of the benefits of static modules, then multiple operations can be provided as properties of a single object. But you've been claiming that it's a *mistake* for modules to support multiple operations (such as 'fs' or 'path' or Math). And I disagree with that.

>> In these cases, there's no natural data abstraction needed, no class or object with methods, just functions. To quote John Carmack, "Sometimes the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function."
> The Carmack quote is exactly why "export one thing" is so important.
> Most modules should be a single function; not several things, not a
> collection of utility methods.

I don't share your interpretation, but let's not quibble over what Carmack meant. What I mean is, JSON.parse and JSON.stringify don't really function as methods. They don't care about `this`. They're just functions, and they happen to be stored on an object because at the time JSON came out, that was the only way to provide multiple functions.

If I want to write a module that provides n functions, what is inherently superior about providing a Thing with n methods, instead of just directly providing the n functions?

BTW, I'm *not* saying that I don't like libraries that use method chaining and abstract types and all that good stuff -- I love it! jQuery, optimist -- these are all great! But they are not the *only* way to write good libraries.

>>>> Moreover, it would be hostile to adding static constructs in the future, such as macros, that can be exported from a module.
>>> Can you elaborate on that?
>> It took me a few days, but I wrote up some rationale for static module resolution on my blog:
> At the risk of seeming like a little bit of a luddite, it seems weird
> to me to make the "modules that export stuff" use case (which we have
> now) less awesome, in favor of the "modules that exports macros and
> types" use case (which is not a compelling problem right now).

I don't see what you're saying is less awesome. I already wrote a blog post about all the ways I think it's more awesome. It's *certainly* more awesome to be able to do callback-free module loading without synchronous I/O, which neither Node nor AMD can do. It's more awesome to be able to put 'export' in front of a local var/function/let/class declaration without having to write separate code elsewhere that constructs an export object. It's more awesome to get early binding optimization. It's more awesome to get built-in error checking for *everyone*, not just the fraction of people that use linters. It's more awesome to support language interoperability. It's more awesome to keep the door open for great features that could make JavaScript better in the future.

> Granted, we don't have that use case because it doesn't exist.  But
> maybe it could be done in a different way that doesn't necessitate
> multiple exports.

It can't.


More information about the es-discuss mailing list