On 12-mar-10, at 09:59, Don wrote:

BCS wrote:
Hello Walter,
2. If a loop is detected, rather than issuing an error message, simply
arbitrarily pick one order and continue constructing.
How about a way to explicitly cut edges in the graph (tagging imports with "pragma(nodep)" or "@nodep" for instance)? That has the same end effect but for only a little more work, removes any non-determinism and allows for easy control of how things are resolved.

I agree. Seems to me that if a circular import exists, it's really something that the programmer needs to think about, and so it's reasonable for it to be explicit.

A really harsh solution would be:

pragma(nodependency, somepackage.somemodule);

The compiler could check that somepackage.somemodule actually defines a static constructor. And it could even check that a circular import situation actually exists. This would force the pragma to be maintained correctly.

I think that the main problem comes from static initializers that are mixed in and by themselves have no circular dependency. So annotations have to be at the static initializer level, not at the module level.

One way to solve this would be to add
@dependOnly(module1,...) static this(){ }

then each module would have 2 dependencies:

* indirectDeps
  imported modules + all dependOnly modules

* directDeps
  look at all static initializers in the module:
  - plain static this() -> add all imported modules as dependency
  - annotated static this -> add all dependOnly dependencies

* allDeps
the list of module that have to be initialized before that module and is build from the previous ones as:
  direct deps + all indirect deps of those modules

more explicitly

allDeps(a){
  deps=[]
  foreach(m in a.directDeps){
    if (m in deps) continue;
    deps~=m;
    addDeps2(m,deps);
  }
  return deps;
}

addDeps2(a, ref deps){
  if (a in deps) return;
  foreach(m in a.indirectDeps){
    if (m in deps) continue;
    deps~=m;
    addDeps2(m,deps);
  }
}

then you can sort the modules that have static initializers (and only those) using:

compare(a,b){
  if (a in b.allDeps){
   if (b in a.allDeps){
     error("non comparable, circular dep between ",a,b);
   }
   return 1;
  }
  if (b in a.allDeps){
    return -1;
  }
  return 0;
}

this is more work, but would be perfectly defined.

conflicting ordering would still be disallowed, but circularly dependent modules can have initializers if all their initializers depend only on modules that are not circularly dependent.

Fawzi

Reply via email to