[phobos] improved module cycle detection algorithm finds existing cycle in phobos, what to do?

Steve Schveighoffer schveiguy at yahoo.com
Fri Nov 5 10:27:22 PDT 2010


----- Original Message ----

> From: Andrei Alexandrescu <andrei at erdani.com>
> 
> On 11/5/10 11:21 AM, Steve Schveighoffer wrote:
> > I think the  cycle as I print it is pretty clear.  What do you find unclear  
>about
> > it?
> 
> Well I didn't look into this closely but essentially  there was this list:
> 
> Cyclic dependency in module std.encoding
> imported  from std.string
> imported from std.dateparse
> imported from  std.date
> imported from std.file
> imported from std.stdio
> imported from  std.functional
> imported from std.range
> imported from  std.exception
> imported from std.conv
> imported from std.array
> imported  from std.algorithm
> imported from std.random *
> imported from  std.range
> imported from std.exception
> imported from std.conv
> imported  from std.array
> imported from std.algorithm
> imported from  std.string
> imported from std.encoding *
> object.Exception: Aborting due to  cycle between (*) elements with module 
>ctors/dtors
> 
> It didn't immediately  give away where the problem is and what steps need to be 
>taken to fix it.  Probably that's why you were compelled to add a natural 
>language  translation:
> 
> > So what this is saying, is std.encoding indirectly  imports std.random, 
which
> > indirectly imports std.encoding, and both of  these modules contain shared 
>module
> > ctors.  I manually verified the  cycle path, and that shared ctors exist, so 
>it
> > is a real cycle.

Yeah, it's an interesting problem.  Because there are all these 
"non-participating" imports between the two modules with static ctors.  You need 
to show them and the order they go in, so you can see how the imports happen 
(otherwise, you are clueless as to which import is the problem), it makes the 
list really large, even though it's technically a 2-element cycle.

> I  also find the passive tense backwards. So I guess I'd format the message as  
>follows:
> 
> =============
> Cyclic dependency: std.encoding imports  std.random and vice versa, and both 
>define module constructors. Details ("<-"  means "imports"):
> 
> std.encoding <- std.string <- std.algorithm <-  ... <- std.random
> std.random <- std.algorithm <- ... <-  std.encoding
> =============

It's printed the way it is because I'm essentially unwinding the call stack, 
printing imports as I return from the depths of the search.  So it's printed 
backwards.  I wanted to avoid allocating separate memory just to be able to 
print it, so I think it's good enough to print backwards.  Therefore, your first 
message (before the import graph) might be difficult to display.  However, I 
think I can get it to work, but it will just print after the long-form of the 
cycle, is that OK?

Also note that it's not always a 2-element cycle, it could be an N element 
cycle, where N is up to the entire number of modules in the exe.

> Long chains can be improved by e.g.  reformatting to one import per line:
> 
> std.encoding <-  std.string
>              <-  std.algorithm
>              <- ...
>               <- std.random
> std.random <-  std.algorithm
>            <- ...
>             <- std.encoding
> 
> Just a thought.

I like the idea of using tabs to delineate 'non-participating' modules, but I'm 
unsure if just doing this makes it clear.  Maybe if I put the non-participating 
modules in parentheses?  Anyone else have an idea of how to print it?

> Anyway, currently the static ctor in std.random  is:
> 
> shared static this()
> {
>     ulong s;
> 
>      version(Win32)
>     {
>          QueryPerformanceCounter(&s);
>     }
>      version(Posix)
>     {
>         //  time.h
>         // sys/time.h
> 
>          timeval tv;
>         if (gettimeofday(&tv,  null))
>         {   // Some error happened - try  time() instead
>             s =  core.sys.posix.sys.time.time(null);
>         }
>          else
>         {
>              s = cast(ulong)((cast(long)tv.tv_sec << 32) +  tv.tv_usec);
>         }
>     }
>      //rand_seed(cast(uint) s, cast(uint)(s >> 32));
> }
> 
> As the  last line is already commented out _and_ rand_seed is deprecated 
>anyway, you may  want to simply remove the  constructor!

Haha! will do :)

-Steve



      


More information about the phobos mailing list