Modules, Concatenation, and Better Solutions

John J Barton johnjbarton at johnjbarton.com
Tue Oct 16 20:38:59 PDT 2012


On Tue, Oct 16, 2012 at 7:10 PM, David Herman <dherman at mozilla.com> wrote:
> On Oct 16, 2012, at 4:51 PM, John J Barton <johnjbarton at johnjbarton.com> wrote:
...
>
> Concrete example: Even and Odd modules refer to each other, but the import statements occur after some initialization:
>
>     module Odd {
>         export let odd = function(x) {
>             return x === 0 ? false : !even(x - 1);
>         }
>         import even from Even; // force execution of Even here, if it hasn't already

Ah, I see the import has three possible duties here, 1) declaration of
|even| from Even 2) definition of |even| 3) execution of module code.
Its that last category that cause the issues in this example: the
circular value isn't used until the next stmt.

>         export let b = odd(17);
>     }
>     module Even {
>         export let even = function(x) {
>             return x === 0 || !odd(x - 1);
>         }
>         import odd from Odd; // force execution of Odd here, if it hasn't already
>         export let b = even(17);
>     }
>     console.log(Odd.b);
>
> With semantics (a), this executes like so:
>
> - start executing Odd
> - initialize Odd.odd
> - start executing Even
> - initialize Even.even
> - try to start executing Odd (but it's already started, so don't)
> - initialize Even.b by calling Even.even
> - initialize Odd.b by calling Odd.odd
>
> And everything succeeds. With semantics (b), regardless of how we break the tie in a cycle, this will fail, because it will try to call either Odd.odd or Even.even before it has initialized the function. Say it starts executing Odd first. It would do this:
>
> - start executing Odd
> - initialize Odd.odd
> - initialize Odd.b by calling Even.even
> - error: Even.even is not yet initialized
>
> So semantics (a) makes it more possible to make a cyclic dependency work, but it's still subtle if you're trying to let them refer to each other in top-level initialization code: you have to make sure to carefully place the imports late enough that the relevant pieces of each modules will have adequately initialized.

I'm surprised by (b). A behavior I would expect from a module loader (c)
 - start executing Odd
 - initialize Odd.odd
 - start executing Even
 - initialize Even.even
 - try to start executing Odd
 - error: Odd has not completed (circular).
Unlike (b) we load and execute Even until we discover the cycle.  (b)
seems to declare Even.even but rely on some other mechanism to define
it.

I guess that all three allow Even/Odd cycles without the execution of b.

I guess (a) excludes later standardization of (b) or (c) but not the reverse.

jjb


More information about the es-discuss mailing list