Brian Di Palma (2014-10-05T15:51:39.000Z)
I'm probably not understanding all the issues here but I'm also not
explaining my suggestion well either.

The way I see the two issues you raised is like this.

1) I think you mean that a parser wants to fail quickly if it comes
across an identifier that was not previously declared as an import but
that could be declared as one deeper in the module file? The simple
solution to that problem is to not allow binding references before
their import statements.

99.9% of modules will declare their imports at the top of the file
anyway, most developers won't come across this restriction very often.
It doesn't take away functionality, it's a useless degree of freedom
and I can't think of any language where it's good practice to
import/require etc anywhere but at the head of a module/class.

I imagine these fast parsers work top down as the packets are streamed
in from the network so this rule should work well for them?

2) I didn't explain this part well. I meant for the "@global" import
to be a special one who's bindings will not go through the same checks
that other modules do. In a browser importing global would return
window.

This should make it trivial to upgrade current code to ES6 modules
while still allowing much stricter checks in modules.
You would use tools that take the ES5 code and scan it for free
identifiers and import them from "@global".
This then allows you to gradually move them all into ES6 modules.

import * as global, {Date, XMLHttpRequest} from "@global";

All bindings provided by "@global" bypass the normal bindings checks.

Think of it as a reverse "use strict", currently to the do the right
thing developers have to add an extra line at the top of all their
scripts.
With ES6 modules they should instead be required to add an extra line
to do the wrong but temporarily necessary wrong thing.

Adding this extra line is highly amenable to automation/tooling which
developers will be using anyway when moving to ES6 modules.

With time this line will be removed as their code is moved into
modules or new versions of global classes are provided in standard
modules.
This would allow developers to still use "Date" as their constructor
and not have it accidentally use the older version if a new one is
added to standard modules.

So by default an ES6 module starts of with a totally clean slate, it
has no external state in its scope.
Only if the developer chooses will the module be exposed to the
madness of the global scope.

Would this help macros or typing to be added to those modules with no
access to the global?
That would be a nice carrot to get developers to try and delete that
line at the top of their module.

B.


On Fri, Oct 3, 2014 at 9:18 PM, Brendan Eich <brendan at mozilla.org> wrote:
> Brian Di Palma wrote:
>>
>> The recent thread on throwing errors on mutating immutable bindings
>> touched upon the fact that there is no static unresolvable reference
>> rejection in modules.
>> I was wondering if that was down to needing to allow access to
>> properties set on the global object?
>>
>> If that's the case why could you not just import the global into a module
>> scope?
>> Just like you import module meta data the module system could have a
>> way of providing you the global object if you import it.
>> That would mean that any reference that is accessed via the global
>> import can't be checked but every other one can.
>>
>> Something like
>>
>>
>> import * as global from "@global";
>>
>> const myValue = global.myGlobalFunction(); //Special won't be checked
>> can be mutated by everyone, big red flag in code reviews.
>>
>> function test() {
>>      x = 10; //Static error, we know this is not an access to a global
>> x as it must be accessed via global.
>> }
>>
>>
>> Could this work?
>
>
> The problem this doesn't solve is the one Andreas Rossberg raised (at a past
> TC39 meeting, and just the other day here): browser-based implementations
> must parse lazily and super-fast, they cannot be presumed to be able to
> afford binding checks. Someone should go super-hack a binding checker that
> doesn't degrade page load perf, or other metrics.
>
> Absent such evidence, there are two strikes against what you propose: 1)
> performance effects of binding checking when parsing; 2) whether async
> script loads make global bindings unordered and so not generally worth
> trying to check.
>
> /be
domenic at domenicdenicola.com (2014-10-15T18:56:24.087Z)
I'm probably not understanding all the issues here but I'm also not
explaining my suggestion well either.

The way I see the two issues you raised is like this.

1. I think you mean that a parser wants to fail quickly if it comes across an identifier that was not previously declared as an import but that could be declared as one deeper in the module file? The simple solution to that problem is to not allow binding references before their import statements.

   99.9% of modules will declare their imports at the top of the file anyway, most developers won't come across this restriction very often. It doesn't take away functionality, it's a useless degree of freedom and I can't think of any language where it's good practice to import/require etc anywhere but at the head of a module/class.

   I imagine these fast parsers work top down as the packets are streamed in from the network so this rule should work well for them?

2. I didn't explain this part well. I meant for the "@global" import to be a special one who's bindings will not go through the same checks that other modules do. In a browser importing global would return window.

   This should make it trivial to upgrade current code to ES6 modules while still allowing much stricter checks in modules. You would use tools that take the ES5 code and scan it for free identifiers and import them from "@global". This then allows you to gradually move them all into ES6 modules.

   ```js
   import * as global, {Date, XMLHttpRequest} from "@global";
   ```

   All bindings provided by "@global" bypass the normal bindings checks.

   Think of it as a reverse "use strict", currently to the do the right thing developers have to add an extra line at the top of all their scripts. With ES6 modules they should instead be required to add an extra line to do the wrong but temporarily necessary wrong thing.

   Adding this extra line is highly amenable to automation/tooling which developers will be using anyway when moving to ES6 modules.

   With time this line will be removed as their code is moved into
modules or new versions of global classes are provided in standard
modules.
This would allow developers to still use "Date" as their constructor
and not have it accidentally use the older version if a new one is
added to standard modules.

   So by default an ES6 module starts of with a totally clean slate, it
has no external state in its scope.
Only if the developer chooses will the module be exposed to the
madness of the global scope.

Would this help macros or typing to be added to those modules with no
access to the global?
That would be a nice carrot to get developers to try and delete that
line at the top of their module.