Written Proposal for "package" Keyword for ES20XX Imports

Logan Smyth loganfsmyth at gmail.com
Thu Feb 23 00:53:50 UTC 2017


> So it sounds like this TDZ error would be at runtime as opposed to
compile-time

Correct, since `extends`, computed properties, and decorators all require
runtime behavior, class declarations are initialized a runtime when
execution reaches them, unlike function declarations, where initialization
can be hoisted.

> would imply the ES6 spec does not truly support circular dependencies

ES6 modules have no explicit handling of circular dependencies. What they
do to approach this problem is have imported values reference the current
value of the exported variable, rather than the value at the time the
import was evaluated. The common problem with circular dependencies in
CommonJS is that when you call `require`, the exported value might not have
been assigned yet. Because ES6 modules expose live access to the current
value, you don't need to worry about that edge case.

This does not however free you from ensuring that your code initializes all
values in the proper order. In your example, the code is executed like
```
// app.js
console.log("B's reference to A", A);

class B extends A {
  constructor() {
    super();
  }
}

console.log("A's reference to B", B);

class A {
  constructor() {
  }
}

var a = new A();
var b = new B();
```
because of the way the imports in your snippet are ordered. As is clear,
you are trying to extend class `A` before the class declaration has
executed. Since initialization of block-scoped variables is not hoisted,
`class B extends A` will throw because `A` is uninitialized.

> Do you have a link to where this is referenced?

The TDZ behavior is the standard behavior of block-scoped values. There is
no special logic around this for imports.

> Babel is not entirely incorrect

Babel's behavior essentially treats `class A {}` like `var A = class A {}`,
hence the `undefined` value. That is not entirely correct, but the ordering
of the imports is correct. There are cases where Babel is limited in
implementing ES6's semantics 100%, but they are all around the behavior of
live re-exports like `export * from 'foo';`.

On Wed, Feb 22, 2017 at 1:03 PM, Greg McLeod <cleod9 at gmail.com> wrote:

> I'll point out that Babel doesn't follow spec perfectly because it can't
>> transpile the bindings correctly in the case of synchronously executed code
>> with circular dependencies. That's a CommonJS limitation that Babel can't
>> work around any more than it already does.
>
>
> @Isiah Is that so? Babel is leading the charge in terms of transpilers
> right now, so that's unfortunate. Anyway I did some quick Googling and
> found a couple of things related to the subject:
>
> https://github.com/webpack/webpack/issues/1788
> https://esdiscuss.org/topic/how-to-solve-this-basic-es6-modu
> le-circular-dependency-problem
>
> While it's evident people have been encountering this for quite some time,
> it seems like the solutions up until now have been mostly workarounds. My
> hope is that a "package" keyword could tackle this kind of thing at more of
> a holistic level for bundled applications.
>
> What does the *spec* say should happen in that situation? (You've clearly
>> been into it in some detail.) As opposed to what Babel does, since of
>> course Babel while excellent is working with some limitations...?
>
>
> @T.J. Good question, see below my response to Logan
>
> It would be a TDZ error, rather than `undefined`, in a real implementation
>> of block scoping + ES6 modules. The ordering still means that `A` won't
>> exist when `class B extends A` runs.
>
>
> @Logan So it sounds like this TDZ error would be at runtime as opposed to
> compile-time, correct? Do you have a link to where this is referenced? Both
> cases would imply the ES6 spec does not truly support circular
> dependencies, and that Babel is not entirely incorrect
>
>
> On Wed, Feb 22, 2017 at 1:18 PM, Logan Smyth <loganfsmyth at gmail.com>
> wrote:
>
>> > What does the *spec* say should happen in that situation?
>>
>> It would be a TDZ error, rather than `undefined`, in a real
>> implementation of block scoping + ES6 modules. The ordering still means
>> that `A` won't exist when `class B extends A` runs.
>>
>> On Wed, Feb 22, 2017 at 10:00 AM, T.J. Crowder <
>> tj.crowder at farsightsoftware.com> wrote:
>>
>>> On Wed, Feb 22, 2017 at 5:50 PM, Isiah Meadows <isiahmeadows at gmail.com>
>>> wrote:
>>>
>>>> I'll point out that Babel doesn't follow spec perfectly because it
>>>> can't transpile the bindings correctly in the case of synchronously
>>>> executed code with circular dependencies. That's a CommonJS limitation that
>>>> Babel can't work around any more than it already does.
>>>>
>>> I was wondering about that. Greg, re your example where you said:
>>>
>>> In the latest Babel the above code fails to run on the first line of
>>>> app.js (at the time it attempts to execute `_inherits(B, _A);`.). This is
>>>> because "A" is undefined in module b.js due to the circular dependency. In
>>>> this case Babel basically executed code in the incorrect order for this to
>>>> be able to work.
>>>
>>>
>>> What does the *spec* say should happen in that situation? (You've
>>> clearly been into it in some detail.) As opposed to what Babel does, since
>>> of course Babel while excellent is working with some limitations...?
>>>
>>> -- T.J. Crowder
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170222/8d9c70c9/attachment-0001.html>


More information about the es-discuss mailing list