On Jan 30, 2012, at 12:09 PM, Andreas Rossberg wrote:

> (Just a quick reply, because I'm in a bit of a hurry.)
> 
> On 30 January 2012 19:17, Allen Wirfs-Brock <[email protected]> wrote:
>>>> 
...
>>>> 
> 
> The analysis is not as straightforward as it might seem. In particular, this:
> 
>> The exported name list of a module can be generated while the module is 
>> parsed
> 
> unfortunately is not true, because of (1) alias bindings, and (2)
> import *. For example, with
> 
>  module A = B.C

Dave/Sam, it would be nice if we had up to date syntax at 
http://wiki.ecmascript.org/doku.php?id=harmony:modules 

> 
> you won't know what A exports before you haven't analysed B and its
> nested C, which might come later in the program. And those can
> recursively refer to A, which might require you knowing what A
> exports. Here is a more messed up, random example:
> 
> 1  module A = B.C
> 2  module D { ... }
> 3  module B {
> 4     let x = B.E.x
> 5     import * from A
> 6     export module B {
> 7       export module E = D
> 8       export module C {
> 9         export module D { ... }
>      }
>    }
>  }

I added line numbers above for reference.  I think there is a basic bug in the 
above that may just be a typo.  "B" reference in line 1 must refer to the 
module defined in line 3.  Hence "B.C" must refer to an export of "C" from that 
module. However, the only export from that module is line 6 which exports "B" 
so the "B.C reference in line 1 is invalid.  This does require any circular 
analysis and line 5 doesn't impact it. 

To get around this  this issue, I looked at assuming that line 6 wasn't really 
intended to be there but that seems to break your example in other ways.  What 
did you really have in mind?

> 
> You couldn't tell which D is aliased by E before processing C and so
> on. In general, it's all recursive, so a simple AST traversal alone,
> in whatever order, won't do. Instead you need to collect and solve
> constraints. In terms of type inference, you infer and unify
> (principal) types.

I agree that * imports complicate matters.  I thought there had been discussion 
at some point about eliminating them, but I'm not yet convinced that by 
themselves they turn this into a constraint solving problems.  In stead I think 
that we need appropriate static restrictions to ensure that it can never be 
such a problem.  If it takes solving to understand module compositions then we 
have created a too power model of module composition.  If the module linkages 
aren't pretty damn obvious to both the writer and the reader, then we've done 
something wrong.

I'm actually not a bit fan of using nesting to do module wiring, but I don't 
think it has result in needing constraint solving to understand the wiring.

> 
> 
>>>> 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.
>>> 
>>> You need a new uninitialized binding for all identifiers in the
>>> module's local scope, not just the exported ones.
>> The non-exported declarations within a module don't need to be instantiated 
>> until module initialization. You probably could instantiate them durning my 
>> module instantiation step but I'm trying to only identify what must happen 
>> at that step.

I was really thinking about non-module declarations  when I wrote the above 
statement.  Module alias declarations like in these examples do lead to a more 
complex traversal.  I have to think about is some more.

> 
> I'm not so sure. You could export parts of a local module:
> 
> module A {
>  module B { export module C { ... } }
>  export module C = B.C
> }
> module C = A.C
> 
> 
>>>> 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.
>>> 
>>> It's not quite that simple. Recursive initialization does not suffice,
>>> because there can be arbitrary import/export/aliasing cycles (e.g., b
>>> could import from a as well). Consequently, you generally need to
>>> create the instance object for _all_ modules in the program first,
>>> before you can start initializing _any_ of them (or the toplevel, for
>>> that matter).
>> 
>> I'm trying to demonstrate an algorithm that takes care of this.  Give me a 
>> specific example that you don't think works.
> 
> If I understand your description correctly, then consider this:
> 
>  module A { export module C = B.C; export module D { ... } }
>  module B { export module C { ... }; export module D = A.D }

Sold, it certainly does look like that modules need to be identified and linked 
before evaluation starts.

that feels to me link a distinct pass.

Allen
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to