<div dir="ltr"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span style="font-size:12.8px">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.</span></blockquote><div><br></div><div>Ahh, I see. Importing B before A in app.js does take care of the issue in Babel. And by placing additional console logs in the constructor I can see that A goes from being initially undefined to being valid by the time an instance of B is created. Definitely the utility of live exports.<br><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span style="font-size:12.8px">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';`.</span></blockquote><div><br></div><div>Thanks for the additional insight. When I first started thinking about a package operator a couple of years ago, it was definitely behaviors like these that I wanted to remove from the list of daily JS development nuances. I've found that this type of dependency issue just simply doesn't occur in languages like C#/Java/AS3 because of how restricted those languages are at the top level scope. The proposal presents the package keyword in JS as an opt-in way to impose a similar restriction, but with the goals of improving static analysis potential of code and making circular dependency bugs a thing of the past.<br><br>I should also note that the code-snippet in the Gist demonstrating the implementation of "package" is actual working ES5. The code allows the circular imports example I wrote without the need for even a live exports object.<br></div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Feb 22, 2017 at 7:53 PM, Logan Smyth <span dir="ltr"><<a href="mailto:loganfsmyth@gmail.com" target="_blank">loganfsmyth@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><span class="">> <span style="font-size:12.8px">So it sounds like this TDZ error would be at runtime as opposed to compile-time</span><div><span style="font-size:12.8px"><br></span></div></span><div><span style="font-size:12.8px">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.</span></div><span class=""><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">> </span><span style="font-size:12.8px">would imply the ES6 spec does not truly support circular dependencies</span></div><div><span style="font-size:12.8px"><br></span></div></span><div><span style="font-size:12.8px">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.</span></div><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">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</span></div><div><span style="font-size:12.8px">```</span></div><div><div style="font-size:12.8px"><div>// app.js<span class=""><br style="font-size:12.8px"><span style="font-size:12.8px">console.log("B's reference to A", A);</span><br style="font-size:12.8px"><br style="font-size:12.8px"></span><span class=""><span style="font-size:12.8px">class B extends A {</span><br style="font-size:12.8px"><span style="font-size:12.8px">  constructor() {</span><br style="font-size:12.8px"><span style="font-size:12.8px">    super();</span><br style="font-size:12.8px"><span style="font-size:12.8px">  }</span><br style="font-size:12.8px"><span style="font-size:12.8px">}</span></span></div><div><br style="font-size:12.8px"><span class=""><span style="font-size:12.8px">console.log("A's reference to B", B);</span><br style="font-size:12.8px"><br style="font-size:12.8px"></span><span style="font-size:12.8px">class A {</span><br style="font-size:12.8px"><span style="font-size:12.8px">  constructor() {</span><br style="font-size:12.8px"><span style="font-size:12.8px">  }</span><br style="font-size:12.8px"><span style="font-size:12.8px">}</span></div><span class=""><div><span style="font-size:12.8px"><br></span></div><div>var a = new A();<br>var b = new B();</div></span></div></div><div><span style="font-size:12.8px">```</span></div><div><span style="font-size:12.8px">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.</span></div><span class=""><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">> </span><span style="font-size:12.8px">Do you have a link to where this is referenced?</span></div><div><span style="font-size:12.8px"><br></span></div></span><div><span style="font-size:12.8px">The TDZ behavior is the standard behavior of block-scoped values. There is no special logic around this for imports.</span></div><span class=""><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">> </span><span style="font-size:12.8px">Babel is not entirely incorrect</span></div><div><span style="font-size:12.8px"><br></span></div></span><div><span style="font-size:12.8px">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';`.</span></div></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Feb 22, 2017 at 1:03 PM, Greg McLeod <span dir="ltr"><<a href="mailto:cleod9@gmail.com" target="_blank">cleod9@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><span><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">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. </blockquote></span><div><br>@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:<br><br><a href="https://github.com/webpack/webpack/issues/1788" target="_blank">https://github.com/webpack/web<wbr>pack/issues/1788</a><br><a href="https://esdiscuss.org/topic/how-to-solve-this-basic-es6-module-circular-dependency-problem" target="_blank">https://esdiscuss.org/topic/ho<wbr>w-to-solve-this-basic-es6-modu<wbr>le-circular-dependency-problem</a><br><br></div><div>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.<br></div><div><span><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span style="font-size:12.8px">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...?</span></blockquote></span><div><br>@T.J. Good question, see below my response to Logan<span><br><br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span style="font-size:12.8px">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.</span></blockquote></span><div><br>@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<br></div><br></div></div></div><div class="m_-5832098897865265393HOEnZb"><div class="m_-5832098897865265393h5"><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Feb 22, 2017 at 1:18 PM, Logan Smyth <span dir="ltr"><<a href="mailto:loganfsmyth@gmail.com" target="_blank">loganfsmyth@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><span>> <span style="font-size:12.8px">What does the *spec* say should happen in that situation?</span><div><span style="font-size:12.8px"><br></span></div></span><div><span style="font-size:12.8px">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.</span></div></div><div class="m_-5832098897865265393m_-6133059992030210216HOEnZb"><div class="m_-5832098897865265393m_-6133059992030210216h5"><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Feb 22, 2017 at 10:00 AM, T.J. Crowder <span dir="ltr"><<a href="mailto:tj.crowder@farsightsoftware.com" target="_blank">tj.crowder@farsightsoftware.c<wbr>om</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span>On Wed, Feb 22, 2017 at 5:50 PM, Isiah Meadows <span dir="ltr"><<a href="mailto:isiahmeadows@gmail.com" target="_blank">isiahmeadows@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><p dir="ltr">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.</p></blockquote></span><span><div>I was wondering about that. Greg, re your example where you said:</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span style="font-size:12.8px">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. </span></blockquote><div><span style="font-size:12.8px"><br></span></div></span><div><span style="font-size:12.8px">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...?</span></div><span class="m_-5832098897865265393m_-6133059992030210216m_-5159231074673672651HOEnZb"><font color="#888888"><div><span style="font-size:12.8px"><br></span></div><div><span style="font-size:12.8px">-- T.J. Crowder</span></div></font></span></div></div></div>
</blockquote></div><br></div>
</div></div></blockquote></div><br></div>
</div></div></blockquote></div><br></div>
</div></div></blockquote></div><br></div>