What sorts of things cause cyclic dependencies?

spir denis.spir at gmail.com
Thu Oct 14 10:28:28 PDT 2010


On Thu, 14 Oct 2010 06:03:05 +0000 (UTC)
"Lars T. Kyllingstad" <public at kyllingen.NOSPAMnet> wrote:

> On Thu, 14 Oct 2010 05:53:51 +0000, Lars T. Kyllingstad wrote:
> 
> > On Wed, 13 Oct 2010 21:25:15 -0700, Jonathan M Davis wrote:
> > 
> >> Okay. in the code that I'm working on at the moment, I get an exception
> >> saying that a cyclic dependency was detected but no information
> >> whatsoever as to where it is or what it means. I haven't been able to
> >> find much information on them other than some discussions of making it
> >> so that the compiler detects them at compile time. I have yet to figure
> >> out _what_ it is that is causes such errors. Could someone clue me in?
> >> It's really hard to track down a bug when the error only tells you that
> >> there's a bug and doesn't say anything about where it happens, and I
> >> have no clue what sort of things can be cyclically dependent.
> > 
> > 
> > Say you have two modules, a and b.  Both have static constructors, and a
> > imports b:
> > 
> >   // a.d
> >   module a;
> >   import b;
> >   static this() { ... }
> > 
> >   // b.d
> >   module b;
> >   static this() { ... }
> > 
> > The language is then defined so that b's constructor is run before a's,
> > since a depends on b.  But what happens if b imports a as well?  There
> > is no way to determine which constructor to run first, so the runtime
> > throws a "cyclic dependency" exception.
> 
> 
> I should mention that this can happen with larger cycles as well, i.e. "a 
> imports b, b imports c, c imports ..., ... imports a".  This can make 
> some cyclic dependencies very hard to track down.
> 
> There was a discussion about this on the Phobos mailing list a few months 
> ago:
> 
>   http://lists.puremagic.com/pipermail/phobos/2010-June/thread.html#949
> 
> -Lars


I'm totally new to D, but have some real-life experience with circular imports. A typical case is with unit testing. Say you design a parsing lib, with (among others) a module defining Pattern types and another for (parse tree) Nodes, wich are thee results of successful pattern matches.
To test Patterns, no issue, since it already imports Nodes for normal process. But testing Nodes introduces a circular dependance, only for testing, because the ordinary way to produce a node, and thus to be able to test its functionality, is to create a Pattern and run its match method against source text.
2 solutions I know of:
* create fake Pattern types inside the Nodes module, just for testing
* export Nodes' test routines into a third module that imports both Patterns and Nodes, but is not import.
That's probably why many libraries have loads of separated test* unittest modules. But I prefere to have tests locally written in the module itself (which well seems to be the intention of D's testing features).

Some static languages (eg freepascal) allow mutual dependance as long as at least one module (M1) uses imported elements of the other (M2) on the implementation side only (not in the interface). This allows the compiler initially constructing the interface of M1 (without any mention of M2), to be imported by M2. Then, M2 can be fully constructed, and imported into M1 for the needs of its implementation only.


Denis 
-- -- -- -- -- -- --
vit esse estrany ☣

spir.wikidot.com



More information about the Digitalmars-d-learn mailing list