www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - how to avoid "cycle detected"?

reply "aki" <aki google.com> writes:
Following code causes run-time error.
How can I use static this() without causing error?
It's difficult to avoid this situation because
actual code is more complex.

file main.d:
void main() {
}

file a.d:
import b;
class A {
	static this() {}
};

file b.d:
import a;
class B {
	static this() {}
};

object.Exception src\rt\minfo.d(162): Aborting: Cycle detected 
between modules w
ith ctors/dtors:
a -> b -> a
Jul 01 2015
next sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
On Wed, 01 Jul 2015 09:09:52 +0000, aki wrote:

 Following code causes run-time error.
 How can I use static this() without causing error?
you currently can't, sorry.=
Jul 01 2015
prev sibling next sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Wednesday, July 01, 2015 09:09:52 aki via Digitalmars-d-learn wrote:
 Following code causes run-time error.
 How can I use static this() without causing error?
 It's difficult to avoid this situation because
 actual code is more complex.

 file main.d:
 void main() {
 }

 file a.d:
 import b;
 class A {
   static this() {}
 };

 file b.d:
 import a;
 class B {
   static this() {}
 };

 object.Exception src\rt\minfo.d(162): Aborting: Cycle detected
 between modules w
 ith ctors/dtors:
 a -> b -> a
Modules which have static constructors (or destructors) cannot import each other, because the runtime has no way of knowing which order they should be run in or even if they _can_ be run in an order that guarantees that you don't use any variables before they're initialized. So, you either need to fix it so that your modules with static constructors aren't importing each (even indirectly), or you need to stop using static constructors in at least one of them. The result of this seems to often be that you should avoid static constructors where reasonably possible, but if your modules are independent enough, they should be fine. They _do_ need to be fairly independent of each other though, or you'll probably run into a problem with static constructors and cyclical imports eventually. - Jonathan M Davis
Jul 01 2015
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 7/1/15 5:09 AM, aki wrote:
 Following code causes run-time error.
 How can I use static this() without causing error?
 It's difficult to avoid this situation because
 actual code is more complex.

 file main.d:
 void main() {
 }

 file a.d:
 import b;
 class A {
      static this() {}
 };

 file b.d:
 import a;
 class B {
      static this() {}
 };

 object.Exception src\rt\minfo.d(162): Aborting: Cycle detected between
 modules with ctors/dtors:
 a -> b -> a
You need to either factor out the static constructors to put them in a leaf module, replace one of them with intializers, or remove one of them. It can be an exercise in ugly coding, but you can fix this. I know it wasn't specifically asked, but the reason it exists is simple: class A { static int x; static this() { x = B.x + 5;} } ... class B { static int x; static this() { x = A.x + 5;} } The runtime cannot introspect the code to detect the circular dependency, so it makes a conservative decision. I'm waiting on an introduction of RTInfo for modules [1] to allow us to mark static ctors as standalone, then we can probably fix this problem through a sort of "trust the programmer" mechanism. -Steve [1] https://issues.dlang.org/show_bug.cgi?id=10023
Jul 01 2015
parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Wednesday, July 01, 2015 08:52:38 Steven Schveighoffer via
Digitalmars-d-learn wrote:
 The runtime cannot introspect the code to detect the circular
 dependency, so it makes a conservative decision. I'm waiting on an
 introduction of RTInfo for modules [1] to allow us to mark static ctors
 as standalone, then we can probably fix this problem through a sort of
 "trust the programmer" mechanism.
I wouldn't mind that, but Walter shot that idea down previously when I was arguing for adding a way to the language to tell the compiler that a static constructor didn't depend on anything else. He didn't want a "trust the programmer" mechanism in this case. I don't remember what his arguments were though. - Jonathan M Davis
Jul 01 2015
next sibling parent "aki" <aki google.com> writes:
On Wednesday, 1 July 2015 at 22:25:48 UTC, Jonathan M Davis wrote:
 On Wednesday, July 01, 2015 08:52:38 Steven Schveighoffer via 
 Digitalmars-d-learn wrote:
 The runtime cannot introspect the code to detect the circular 
 dependency, so it makes a conservative decision. I'm waiting 
 on an introduction of RTInfo for modules [1] to allow us to 
 mark static ctors as standalone, then we can probably fix this 
 problem through a sort of "trust the programmer" mechanism.
I wouldn't mind that, but Walter shot that idea down previously when I was arguing for adding a way to the language to tell the compiler that a static constructor didn't depend on anything else. He didn't want a "trust the programmer" mechanism in this case. I don't remember what his arguments were though. - Jonathan M Davis
Thanks for the discussion, now I understand there are technical difficulties. I have to give it a name like void staticInit(); and call it manually from main(). aki.
Jul 02 2015
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 7/1/15 6:25 PM, Jonathan M Davis via Digitalmars-d-learn wrote:
 On Wednesday, July 01, 2015 08:52:38 Steven Schveighoffer via
Digitalmars-d-learn wrote:
 The runtime cannot introspect the code to detect the circular
 dependency, so it makes a conservative decision. I'm waiting on an
 introduction of RTInfo for modules [1] to allow us to mark static ctors
 as standalone, then we can probably fix this problem through a sort of
 "trust the programmer" mechanism.
I wouldn't mind that, but Walter shot that idea down previously when I was arguing for adding a way to the language to tell the compiler that a static constructor didn't depend on anything else. He didn't want a "trust the programmer" mechanism in this case. I don't remember what his arguments were though.
With RTInfo for modules, we don't need any additional language support. In Dconf '14, Walter said it was a good idea to add the RTInfo support for modules. I don't know if he voiced an opinion on the usage of it for flagging whether the static ctors are all standalone. But with support for modifying the runtime to reflect compile-time traits, we can at least play around with it. There are some things that are so obviously not dependent on anything (like initializing an AA), it's really quite annoying to have the runtime conservatively flag those as error. -Steve
Jul 02 2015
parent Jonathan M Davis via Digitalmars-d-learn writes:
On Thursday, July 02, 2015 06:56:26 Steven Schveighoffer via
Digitalmars-d-learn wrote:
 On 7/1/15 6:25 PM, Jonathan M Davis via Digitalmars-d-learn wrote:
 On Wednesday, July 01, 2015 08:52:38 Steven Schveighoffer via
Digitalmars-d-learn wrote:
 The runtime cannot introspect the code to detect the circular
 dependency, so it makes a conservative decision. I'm waiting on an
 introduction of RTInfo for modules [1] to allow us to mark static ctors
 as standalone, then we can probably fix this problem through a sort of
 "trust the programmer" mechanism.
I wouldn't mind that, but Walter shot that idea down previously when I was arguing for adding a way to the language to tell the compiler that a static constructor didn't depend on anything else. He didn't want a "trust the programmer" mechanism in this case. I don't remember what his arguments were though.
With RTInfo for modules, we don't need any additional language support. In Dconf '14, Walter said it was a good idea to add the RTInfo support for modules. I don't know if he voiced an opinion on the usage of it for flagging whether the static ctors are all standalone. But with support for modifying the runtime to reflect compile-time traits, we can at least play around with it. There are some things that are so obviously not dependent on anything (like initializing an AA), it's really quite annoying to have the runtime conservatively flag those as error.
The last discussion that I had with Walter on supporting a way to tell the compiler that a static constructor did not depend on another module was at least a couple of years ago I'd guess. So, he may have a different opinion on it now, and by using RTInfo, we wouldn't need his approval in quite the same way, so we may very well be able to do it now, but he was against the concept when we discussed it last (I don't think that the fact that we'd be adding language support vs runtime support was really an issue - it was the idea that we'd even have a way for the programmer to do what we're suggesting here by any mechanism). IIRC, part of the problem was the idea that it wouldn't be very hard for code to be marked as independent but inadvertently become depedent later and silent cause problems. In any case, I do tend to like the idea, since as it stands, we have to weed most static constructors out of Phobos, and it can be _very_ annoying, so I would not be averse to exploring the possibility, but just be aware that Walter has opposed it in the past, and it may take some doing to convince him (though maybe he's changed his opinion by now). - Jonathan M Davis
Jul 03 2015
prev sibling parent reply "Kapps" <opantm2+spam gmail.com> writes:
On Wednesday, 1 July 2015 at 09:09:53 UTC, aki wrote:
 Following code causes run-time error.
 How can I use static this() without causing error?
 It's difficult to avoid this situation because
 actual code is more complex.

 file main.d:
 void main() {
 }

 file a.d:
 import b;
 class A {
 	static this() {}
 };

 file b.d:
 import a;
 class B {
 	static this() {}
 };

 object.Exception src\rt\minfo.d(162): Aborting: Cycle detected 
 between modules w
 ith ctors/dtors:
 a -> b -> a
An ugly solution, but the approach used in Phobos is to create something like a_init.d which a.d imports, provided that the static ctors don't actually rely on things from the static ctor of b.
Jul 02 2015
parent "aki" <aki google.com> writes:
On Thursday, 2 July 2015 at 17:21:03 UTC, Kapps wrote:
 An ugly solution, but the approach used in Phobos is to create 
 something like a_init.d which a.d imports, provided that the 
 static ctors don't actually rely on things from the static ctor 
 of b.
How about this idea? Allowing to define sub module in a module. file foo.d: module foo; // nameless module, automatically imported by outer module foo module { int[] needInitialize; static this() { needInitialize = ...; } } // use statically initialized variable needInitialize... Basically, d-lang's module has one-to-one correspondence with file. This new feature breaks this rule, but it's safe because this one is private to module foo. There are no way to import this nameless module by other modules. The purpose is just the alternative to making foo_init.d file. aki.
Jul 02 2015