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

> On 26 January 2012 23:31, Allen Wirfs-Brock <al...@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
> 

_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to