Ambiguity with default exports and live bindings?
/#!/JoePea
joe at trusktr.io
Fri Jul 8 19:22:56 UTC 2016
Interesting. I think it is very intuitive to think that `export default A`
where `A` is a variable would be live. I personally find that live bindings
are very helpful when dealing with circular dependencies.
For example, suppose we have two modules A and B:
```js
// B.js
import A, {defineClassA} from `./A`
if (!A) defineClassA() // this fires, and triggers the error, see A.js.
export default
class B extends A { /* ... */ }
```
```js
// A.js
import someFunction from './other-module'
import B from './B'
let A = null
export default A
if (!A) defineClassA() // this doesn't fire, the error is triggered by B.js
first.
export
function defineClassA() {
someFunction() // Error happens here, triggered from B.js
A = class {
method() {
console.log('B constructor:', B)
}
}
}
```
I was erroneously expecting the export statements to create live bindings,
so that my `defineClassA` call inside of B would cause A to be defined in
case module B evaluates first. But as you can see, that doesn't work.
So, I'll simply now prefer `export {A as default}`, in which case the
modules become
```js
// B.js
import A, {defineClassA} from `./A`
if (!A) defineClassA() // this fires, and triggers the error, see A.js.
class B extends A { /* ... */ }
export {B as default}
```
```js
// A.js
import someFunction from './other-module'
import B from './B'
let A = null
export {A as default}
if (!A) defineClassA() // this doesn't fire, the error is triggered by B.js
first.
export
function defineClassA() {
someFunction() // Error happens here, triggered from B.js
A = class {
method() {
console.log('B constructor:', B)
}
}
}
```
Although I love ES6 modules, I don't think these live binding semantics are
clear or intuitive. Although probably too late and it won't happen, what if
export bindings were more explicit with a `live` keyword?
```js
export {
live bar, // live binding of variable bar
foo // not live, exports value.
}
export // not live
function foo() {}
export live // live
function foo() {}
export default live A // A is a live binding
export default A // exports value
// etc...
```
The reason I suggest this is because JS seems to prefer having meaningful
keywords to make intent clear (for example, we chose to have the `await`
keyword inside `async` functions, but we could have gone the Java route and
used no keywords at all to make it hard to immediately see what is async
and what isn't).
*/#!/*JoePea
On Wed, Jul 6, 2016 at 4:38 PM, Bergi <a.d.bergi at web.de> wrote:
> /#!/JoePea schrieb:
>
>> Is it true one of the following does not create a live binding?
>>
>
> Yes and no.
>
> ```js
>> let A = 123
>> export default A // not a live binding?
>> ```
>>
>
> Actually it does create a live binding - to the variable with the name
> "*default*" which you cannot assign. But yes, the binding `A` is not
> exported.
>
> ```js
>> let A = 123
>> export {A as default} // live binding?
>> ```
>>
>
> Yes.
>
> If so, this seems like large source for unexpected behavior when people
>> create modules. I can imagine people easily overlooking the difference and
>> expecting live bindings in both cases (this already happened to me).
>>
>
> I think people do in general not expect live bindings at all. For
> declarations and the purpose of initialisation order, yes, but not for
> mutable variables. You should export `const`s.
> See also
> http://stackoverflow.com/q/35223111/1048572?what-is-the-difference-between-importing-a-function-expression-or-a-function-declaration-from-a-ES6-module
> .
>
> Kind regards,
> Bergi
>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20160708/9bd2cd19/attachment.html>
More information about the es-discuss
mailing list