Thread overview
how to avoid "cycle detected"?
Jul 01, 2015
aki
Jul 01, 2015
ketmar
Jul 01, 2015
Jonathan M Davis
Jul 01, 2015
Jonathan M Davis
Jul 02, 2015
aki
Jul 03, 2015
Jonathan M Davis
Jul 02, 2015
Kapps
Jul 03, 2015
aki
July 01, 2015
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


July 01, 2015
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.

July 01, 2015
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

July 01, 2015
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
July 01, 2015
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
July 02, 2015
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.

July 02, 2015
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
July 02, 2015
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.

July 03, 2015
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.

July 03, 2015
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