www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Cyclic depency with class static ctor

reply "Frank Benoit (keinfarbton)" <benoit tionex.removethispart.de> writes:
I have project with many classes which also sometimes have static ctors.
Now I get the runtime error "cyclic dependency in module ...".

Is that a bug in the d runtime system, or is it just not documented,
that this runtime error is also possible for static ctors?

Now I have these 300+ ported classes, in 300+ modules. And they import
each other and many of them have a static ctor. What can I do? How can I
resolve the problems?

I can think of the possibility to replace all "static this()" with a
"public static void static_this()" and make a global module where i call
all these ctor in a manual defined order. Is that the way to go?
Oct 26 2006
next sibling parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Frank Benoit (keinfarbton)" <benoit tionex.removethispart.de> wrote in 
message news:ehrblq$2do6$1 digitaldaemon.com...
I have project with many classes which also sometimes have static ctors.
 Now I get the runtime error "cyclic dependency in module ...".

 Is that a bug in the d runtime system, or is it just not documented,
 that this runtime error is also possible for static ctors?

 Now I have these 300+ ported classes, in 300+ modules. And they import
 each other and many of them have a static ctor. What can I do? How can I
 resolve the problems?

Put all the classes in one file. No, seriously. That's the proposed solution.
 I can think of the possibility to replace all "static this()" with a
 "public static void static_this()" and make a global module where i call
 all these ctor in a manual defined order. Is that the way to go?

I've done pretty much the equivalent in a lot of my projects. It's just not really possible to mash together some modules which import each other, without putting most of the project into one module. This error could probably be avoided with a smarter compiler, but now we're getting into QOI (quality of implementation) issues, and maybe not something which could be enforced by the spec..
Oct 26 2006
prev sibling next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Frank Benoit (keinfarbton) wrote:
 I have project with many classes which also sometimes have static ctors.
 Now I get the runtime error "cyclic dependency in module ...".
 
 Is that a bug in the d runtime system, or is it just not documented,
 that this runtime error is also possible for static ctors?

http://www.digitalmars.com/d/module.html#staticorder (under "Order of Static Construction") ----- Cycles (circular dependencies) in the import declarations are allowed as long as not both of the modules contain static constructors or static destructors. Violation of this rule will result in a runtime exception. ----- So it's definitely documented. Not as a bug, but as a limitation. The reason for this is probably so that static constructors can assume imported modules have been properly initialized.
 Now I have these 300+ ported classes, in 300+ modules. And they import
 each other and many of them have a static ctor. What can I do? How can I
 resolve the problems?
 
 I can think of the possibility to replace all "static this()" with a
 "public static void static_this()" and make a global module where i call
 all these ctor in a manual defined order. Is that the way to go?

If you want to go this way, remember you don't have to do this for *all* modules, just the ones involved in a cyclic dependency whose static constructors don't depend on the other ones having been run yet. Then call it from the start of the static constructors of any modules importing it. If there's multiple such modules, make sure it doesn't matter if it's run multiple times, since you can't rely on any module being initialized before another (unless it's imported by it).
Oct 26 2006
parent Carlos Santander <csantander619 gmail.com> writes:
Frits van Bommel escribió:
 Frank Benoit (keinfarbton) wrote:
 
 Now I have these 300+ ported classes, in 300+ modules. And they import
 each other and many of them have a static ctor. What can I do? How can I
 resolve the problems?

 I can think of the possibility to replace all "static this()" with a
 "public static void static_this()" and make a global module where i call
 all these ctor in a manual defined order. Is that the way to go?

If you want to go this way, remember you don't have to do this for *all* modules, just the ones involved in a cyclic dependency whose static constructors don't depend on the other ones having been run yet.

To get a bit of help with this, check out dimple: http://www.shfls.org/w/d/dimple/ The generated graphic shows cyclic dependencies. However, I don't know how well it works with some of the recent additions to D (static import, etc.) -- Carlos Santander Bernal
Oct 26 2006
prev sibling parent reply Walter Bright <newshound digitalmars.com> writes:
Frank Benoit (keinfarbton) wrote:
 I have project with many classes which also sometimes have static ctors.
 Now I get the runtime error "cyclic dependency in module ...".
 
 Is that a bug in the d runtime system, or is it just not documented,
 that this runtime error is also possible for static ctors?
 
 Now I have these 300+ ported classes, in 300+ modules. And they import
 each other and many of them have a static ctor. What can I do? How can I
 resolve the problems?
 
 I can think of the possibility to replace all "static this()" with a
 "public static void static_this()" and make a global module where i call
 all these ctor in a manual defined order. Is that the way to go?

Yes. It isn't possible for the language to really determine the dependencies, so it plays it safe and tries to get all the static ctors run before the module(s) static ctors that import them. With cyclic imports and static ctors in those cycles, this is not possible.
Oct 26 2006
parent reply BCS <BCS pathlink.com> writes:
Walter Bright wrote:
 
 Yes. It isn't possible for the language to really determine the 
 dependencies, so it plays it safe and tries to get all the static ctors 
 run before the module(s) static ctors that import them. With cyclic 
 imports and static ctors in those cycles, this is not possible.

If the rules were changed so that static this functions may only depend on modules imported before them, then a lot of cases could be made to work. <code name="a.d> static this(){writef("A\n");} </code> <code name="b.d> import a; import c; static this(){writef("B\n");} </code> <code name="c.d> import a; static this(){writef("C\n");} import b; </code> <output> A C B </output>
Oct 27 2006
parent reply Walter Bright <newshound digitalmars.com> writes:
BCS wrote:
 Walter Bright wrote:
 Yes. It isn't possible for the language to really determine the 
 dependencies, so it plays it safe and tries to get all the static 
 ctors run before the module(s) static ctors that import them. With 
 cyclic imports and static ctors in those cycles, this is not possible.

If the rules were changed so that static this functions may only depend on modules imported before them, then a lot of cases could be made to work.

I'd rather have fewer order dependencies, not more <g>.
Oct 29 2006
parent reply Kristian <kjkilpi gmail.com> writes:
On Mon, 30 Oct 2006 06:48:55 +0200, Walter Bright  
<newshound digitalmars.com> wrote:

 BCS wrote:
 Walter Bright wrote:
 Yes. It isn't possible for the language to really determine the  
 dependencies, so it plays it safe and tries to get all the static  
 ctors run before the module(s) static ctors that import them. With  
 cyclic imports and static ctors in those cycles, this is not possible.

depend on modules imported before them, then a lot of cases could be made to work.

I'd rather have fewer order dependencies, not more <g>.

Well, generally in programming things must be done in a specific order... ;) What if some other syntax would be used to define the order of static ctors? For example: import a, b, c; after a: before c: static this();
Oct 30 2006
parent reply Walter Bright <newshound digitalmars.com> writes:
Kristian wrote:
 What if some other syntax would be used to define the order of static 
 ctors?
 For example:
 
     import a, b, c;
 
     after a: before c: static this();

I don't think new syntax is justified because Frank's workaround handles the problem nicely.
Oct 30 2006
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Walter Bright" <newshound digitalmars.com> wrote in message 
news:ei5kj0$1p2m$2 digitaldaemon.com...
 Kristian wrote:
 What if some other syntax would be used to define the order of static 
 ctors?
 For example:

     import a, b, c;

     after a: before c: static this();

I don't think new syntax is justified because Frank's workaround handles the problem nicely.

Except that it makes static ctors entirely useless, since you're just emulating them. You end up going back to the way you did it in other languages, and static ctors become a useless feature.
Oct 30 2006
parent reply Walter Bright <newshound digitalmars.com> writes:
Jarrett Billingsley wrote:
 "Walter Bright" <newshound digitalmars.com> wrote in message 
 news:ei5kj0$1p2m$2 digitaldaemon.com...
 Kristian wrote:
 What if some other syntax would be used to define the order of static 
 ctors?
 For example:

     import a, b, c;

     after a: before c: static this();

the problem nicely.

Except that it makes static ctors entirely useless, since you're just emulating them. You end up going back to the way you did it in other languages, and static ctors become a useless feature.

It can appear that way, but there is a crucial point about static constructors. They are most useful when you import a module, and that module *may* or *may not* have some initialization needs that are hidden to you. Static constructors take care of that automatically. The problem here crops up only when they are cyclic imports, i.e. imports that import each other. That means the programmer implementing N that imports M is already familiar with the implementation of M, because M imports N. Therefore, there is no unknown static constructor nor are there any hooks that need to be added to main() by the programmer. Furthermore, the programmer can implement the static constructors for M and N in such a way that the user of M or N still does not need to add any hooks to main(). Essentially, M and N are logically welded into one module for the user. So, static constructors are not useless at all, even when there are cycles that have to be dealt with.
Oct 30 2006
parent "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Walter Bright" <newshound digitalmars.com> wrote in message 
news:ei6795$2d76$1 digitaldaemon.com...
 It can appear that way, but there is a crucial point about static 
 constructors. They are most useful when you import a module, and that 
 module *may* or *may not* have some initialization needs that are hidden 
 to you. Static constructors take care of that automatically.

That's true. Though more times than not, I've run into the cyclic import problem..
 The problem here crops up only when they are cyclic imports, i.e. imports 
 that import each other. That means the programmer implementing N that 
 imports M is already familiar with the implementation of M, because M 
 imports N. Therefore, there is no unknown static constructor nor are there 
 any hooks that need to be added to main() by the programmer. Furthermore, 
 the programmer can implement the static constructors for M and N in such a 
 way that the user of M or N still does not need to add any hooks to 
 main(). Essentially, M and N are logically welded into one module for the 
 user.

It just seems like unnecessary cruft to have to do what Frank mentioned, i.e. to create a "static ctor module" which calls all the static initializations for all the modules in existence. It seems like the compiler would be able to make a much better judgement call about which static ctors depended upon which modules, and would be able to issue a compile-time error if there really were a cyclic static ctor dependency (which, 99% of the time, there _isn't_, which is why it seems completely superfluous to have to manually initialize the modules!). It makes me angry that I can't do something as simple as: module a; import b; int x; static this() { x = 5; } ............... module b; import a; int y; static this() { y = 10; } There is obviously no interdependency between the modules for static initialization, but D throws an error at runtime nonetheless. It seems almost stupid.
Oct 30 2006