order of static constructor execution

Fawzi Mohamed fawzi at gmx.ch
Fri Mar 12 03:06:25 PST 2010


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



More information about the Digitalmars-d mailing list