Design principles for extending ES object abstractions

Luke Hoban lukeh at
Thu Jul 14 00:00:19 PDT 2011

      Well, I think I understand what you're getting at: there's a sense in which generators don't add the ability to do something that's *absolutely impossible* to express in ES5.

      OTOH, generators make it possible to express something that otherwise -- in general -- requires a deep translation (in particular, a CPS transformation of the entire function). This is more than syntactic sugar. This is a new expressiveness that wasn't there before. The slope between Felleisen-expressiveness ("is it possible to do X without a deep transformation?") and Turing-expressiveness ("is it possible to do X at all?") is a slippery one.

      I don't want to quibble about philosophical pedantry, but that's really all I mean by my shyness about General Principles. They're strictly *harder* to decide on than the problem at hand. It's too easy to lose focus and waste time arguing abstractions. And then even when we agree on general principles, when we get into concrete situations it's too easy to start quibbling about exactly how to interpret and apply the principles for the problem at hand.

      I prefer to work out from the middle of the maze, learning and refining principles as I go, rather than trying to decide on them all up front.

Agreed.  The principle itself is not really the primary point.  But I do think there is a fairly crisp line that can be drawn at the level of "any observable behaviour of an object that can be created with extended code can also be provided by an object created without using extended code".   Ultimately though, the goal is just to provide the most value to the most users.

      But it should not be necessary to have a callbacky version for builtin modules like "@name" -- the API should include a simple, synchronous way to test for the presence of modules in a loader. So it should be possible to do something like SystemLoader.getLoaded("@name").

That's good to hear.  I do hope we can ultimately make this API even simpler - both for convenient feature-detection and for authoring modular code in normal syntax.  "require('@name')" is a pleasantly simple primitive for modularity - while it may not be possible to be quite so terse in the API, I hope we can move in that direction.

(1) why is a child loader needed?

      Not needed, just the point of the example. Let me make the example more concrete:

      You're writing an online code editor like CodeMirror or ACE, and you want to support the programmer running JS code from within the editor. So you want to run that code in a sandbox, so that it doesn't see the data structures that are implementing the IDE itself. So you create a child loader. Now, within that child loader, you might want the ability to construct some initial modules that make up the initial global environment that the user's code is running in. So you use buildModule to dynamically construct those modules.

      (2) any particular reason why the buildModule and registerModule are separated?

      Because you might want to build a single shared module instance that you register in multiple loaders. These are orthogonal primitives that can be composed. It may also make sense to have conveniences for common operations, layered on top of the primitives.

This use case makes sense.  Though generally the use of child loaders does feel like a <10% case for modules.  I'll be interested in discussing the conveniences for common operations here, once there are more details on the primitives to provide feedback on.

      (3) Would this allow declaring module dependencies for the new module?  As one comparison, the require.js module definition syntax is simpler in terms of APIs, but also requires an extra closure due to module dependencies, which may also be needed in the model above:

          define("m", [], function() {
              return {
                  x: 42,
                  f: function() { ...  }

      I think the more straightforward approach is just to pre-load (and pre-register in the loader, if appropriate) whatever dependencies are needed.

I'm not sure I follow what this would look like.  Why would I need a new loader at all in this case?  I  think I just need to see some more examples to grok how this API is intended to be used.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list