The global object should not be the "global scope instance object"

Allen Wirfs-Brock allen at wirfs-brock.com
Fri Jan 27 17:08:12 PST 2012


On Jan 27, 2012, at 12:07 AM, Andreas Rossberg wrote:

> On 26 January 2012 23:31, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
>> On Jan 26, 2012, at 11:26 AM, Andreas Rossberg wrote:
>>> Module scoping is difficult, especially if you want a semantics that
>>> can be decided efficiently. Moreover, shadowing and recursion (and
>>> every ES6 scope is recursive) don't go together well. And things get
>>> even more interesting with "import *".
>> 
>> Can you give an example of what you mean by "recursive" in this context? Do you mean that a scope can contain references to bindings defined by the scope?
> 
> Yes, every binding sees every other binding in the same scope
> (including itself). It is not clear to me how that can be combined
> with intra-scope shadowing. Which instance of a name would be visible
> where in the same scope?
> 
> There are many programming languages that allow shadowing in the same
> scope, and quite a few that have recursive scopes. But I don't know
> any that would have both. I believe it's asking for trouble.
> 

I played around a bit to see if I could come up with a troublesome example of the sort you may be thinking about.  What I came up with is the follow:

<script>
module a {
   import {x:y} from b;
   module b{
      export let y = x;  //essentially this is let y=y
    }
}
</script>


1)The script is parsed, and static semantic checks are made.  There are no static errors. 
2) module instantiation is performed for the block.  This instantiates each module defined by the top level of the block, instantiating a module includes producing the list of identifiers exported by the module. Each identifier is associated with a new uninitialized binding. Instantiated modules are not initialized (their body is not executed) at this time.
3) An initialized binding for "a" is is created in the top level environment for the script.  (all top level binding are instantiate at this point, if there were any others).  Note that the binding for a is initialized (it reference a module instance object) but the module itself is not yet initialized
4) initialize module a
     5) module instantiation is performed for the body of module a.  This instantiates a module instance for module b with exported identifier "y" and its binding.
     6) An initialized binding for "b" is is created  in module a's inner environment; (but module b is not yet initialized)
     7) An binding for  "x"  is created in module a's inner environment.  The binding is linked to the binding of "y" exported from b.  Both bindings share the same initialization state.  (currently uninitialized)     
     8) initialize module b
            9) The binding for  for "y" that was created when module b was instantiated is added to  module b's inner environment
            10) evaluate the LHS of the exported let;  the binding found for "x" is uninitialized so we throw and the script terminates.

If evaluating LHS didn't have any dependencies upon uninitialized bindings (say it was a constant or a function expression) we would continue as follows:

            11) set the "y" binding to the value of the LHS and mark "y" as initialized, this also mark the "x" binding in module a as initialized
     12) module b is not fully initialized
13) module a is not fully initialized
  
I've only mentally walked through the steps but it looks to me like this process will also work for circular dependencies such as http://wiki.ecmascript.org/doku.php?id=harmony:modules_examples#cyclic_dependencies 

> 
>>> You might get away with duplicate imports in separate scripts, like in
>>> your example. But AFAICS, that essentially amounts to reintroducing
>>> the multiple-scripts-as-nested-scopes idea through the backdoor. Just
>>> consider that in the presence of import shadowing, you could rewrite
>>> 
>>>  let x = e
>>> 
>>> to
>>> 
>>>  module __fresh_name__ { export let x = e }
>>>  import {x} from __fresh_name__
>>> 
>>> and thereby have the same effect as if shadowing was allowed for let.
>> 
>> Huh?
>> 
>> <script>
>> module _fn_ {export let x = e}
>> import {x} from _fn_
>> </script>
>> <script>
>> import {x} from _fn_
>> </script>
>> 
>> seems quite different from
>> 
>> <script>
>> let x=e;
>> </script>
>> <script>
>> let x=e;
>> </script>
> 
> Not if you rewrite each let separately. That gives:
> 
> <script>
> module _fn1_ {export let x = e}
> import {x} from _fn1_
> </script>
> <script>
> module _fn2_ {export let x = e}
> import {x} from _fn2_
> </script>
> 
> And you have two different instances of x, one shadowing the other.
or the 2nd import is illegal because it is a duplicate definition in the common top-level scope,
or the two scripts don't share a common top-level lexical scope and hence the two imported x bindings are distinct but neither shadow the other

Allen

> 
> /Andreas
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120127/50174b39/attachment.html>


More information about the es-discuss mailing list