digitalmars.D - Static constructors in circularly imported modules - again
- Max Samukha (39/39) May 27 2010 There was a discussion about those a while ago that terminated with
- Max Samukha (24/46) May 27 2010 Ok, I've just thought of a way to avoid synchronization (using __gshared...
- Jason House (2/52) May 27 2010 In module b, delete the import of c. In module c, delete the import of b...
- Max Samukha (46/47) May 27 2010 (b.foo and c.foo). I suspect what you really want is one global a.foo?
- Michel Fortin (11/14) May 27 2010 Just a small note...
- Max Samukha (5/8) May 27 2010 That has been the very point of this thread (no pun). In my other post I...
- Max Samukha (8/47) May 28 2010 I'd really appreciate a reply from the language designers. What are the
- Eldar Insafutdinov (2/65) May 29 2010 Why has it become a tradition to ignore uncomfortable questions in these...
There was a discussion about those a while ago that terminated with Andrei's authoritative "it would be a step backward". I am not entirely convinced that there had been a step forward in the first place. Defining static construction order to be determined by the module import graph had been a half step forward. Completely disallowing static construction of circularly imported modules - a half step backward. The result is std.stdiobase and impossibility to initialize static data in mixins without resorting to lazy initialization. I can live with hacks like std.stdiobase when such are possible. What is more critical is initialization of mixins. Restating the problem: module a; mixin template Foo() { static immutable Object foo; shared static this() { foo = cast(immutable)new Object; } } ---- module b; import a; import c; mixin Foo; ---- module c; import a; import b; mixin Foo; In this scenario one is forced to avoid static constructors by lazily initializing foo and using some kind of synchronization, which should be absolutely unnecessary and sometimes is not tolerable. So which of the following is going to happen? 1. The current blinkered design will stay. 2. A solution will be provided before D2 is feature-freezed. Note that I am well aware of http://yosefk.com/c++fqa/ctors.html#fqa-10.12 etc, but simply disallowing static construction is not a good solution for static construction problems.
May 27 2010
On 05/27/2010 01:37 PM, Max Samukha wrote:module a; mixin template Foo() { static immutable Object foo; shared static this() { foo = cast(immutable)new Object; } } ---- module b; import a; import c; mixin Foo; ---- module c; import a; import b; mixin Foo; In this scenario one is forced to avoid static constructors by lazily initializing foo and using some kind of synchronization, which should be absolutely unnecessary and sometimes is not tolerable.Ok, I've just thought of a way to avoid synchronization (using __gshared for simplicity): module a; mixin template Foo() { static __gshared Object foo; // shared foo static Object tlFoo; // thread-local foo Object getFoo() { if (!tlFoo) { synchronized(lock) { if (!foo) foo = new Object; } tlFoo = foo; } return tlFoo; } } There is still unnecessary overhead of accessing and testing the thread-local variable.
May 27 2010
Max Samukha Wrote:There was a discussion about those a while ago that terminated with Andrei's authoritative "it would be a step backward". I am not entirely convinced that there had been a step forward in the first place. Defining static construction order to be determined by the module import graph had been a half step forward. Completely disallowing static construction of circularly imported modules - a half step backward. The result is std.stdiobase and impossibility to initialize static data in mixins without resorting to lazy initialization. I can live with hacks like std.stdiobase when such are possible. What is more critical is initialization of mixins. Restating the problem: module a; mixin template Foo() { static immutable Object foo; shared static this() { foo = cast(immutable)new Object; } } ---- module b; import a; import c; mixin Foo; ---- module c; import a; import b; mixin Foo; In this scenario one is forced to avoid static constructors by lazily initializing foo and using some kind of synchronization, which should be absolutely unnecessary and sometimes is not tolerable. So which of the following is going to happen? 1. The current blinkered design will stay. 2. A solution will be provided before D2 is feature-freezed. Note that I am well aware of http://yosefk.com/c++fqa/ctors.html#fqa-10.12 etc, but simply disallowing static construction is not a good solution for static construction problems.In module b, delete the import of c. In module c, delete the import of b. Your sample code will then compile and run. It probably wouldn't do what you want though; you'll have two globals (b.foo and c.foo). I suspect what you really want is one global a.foo?
May 27 2010
On 05/27/2010 03:47 PM, Jason House wrote:In module b, delete the import of c. In module c, delete the import of b. Your sample code will then compile and run. It probably wouldn't do what you want though; you'll have two globals(b.foo and c.foo). I suspect what you really want is one global a.foo? Two distinct globals. There is a more concrete example: module QObject; class QMetaObject { ... } mixin template Q_OBJECT() { ... immutable(QMetaObject) metaObject() immutable { return staticMetaObject; } static immutable QMetaObject staticMetaObject; shared static this() { staticMetaObject = cast(immutable)QMetaObject.create!(typeof(this)); } } ---- module a; import QObject; import b; class A : QObject { B b; mixin Q_OBJECT; } ---- module b; import QObject; import a; class B : { A a; mixin Q_OBJECT; } When mixed in a class, Q_OBJECT, among other things, associates a global RTTI object with that class. Ideally, this object should be created at program startup. We cannot impose on the user of Q_OBJECT the requirement that a and b should not be circularly imported or that he has to manually call an initialization function etc.
May 27 2010
On 2010-05-27 09:57:30 -0400, Max Samukha <spambox d-coding.com> said:We cannot impose on the user of Q_OBJECT the requirement that a and b should not be circularly imported or that he has to manually call an initialization function etc.Just a small note... In the D/Objective-C bridge, I've resorted to lazy initialization for this kind of thing. This way there is no module constructors and circular imports work as expected. But it isn't thread-safe, and I expect it would be a pain to make lazy initialization thread-safe, although I haven't tried yet. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
May 27 2010
On 27.05.2010 18:38, Michel Fortin wrote:But it isn't thread-safe, and I expect it would be a pain to make lazy initialization thread-safe, although I haven't tried yet.That has been the very point of this thread (no pun). In my other post I supplied a hack that uses two variables, shared and TLS, to reduce the cost of accessing the global. Not ideal at all but at least it requires synchronization only during the first access.
May 27 2010
On 27.05.2010 13:37, Max Samukha wrote:There was a discussion about those a while ago that terminated with Andrei's authoritative "it would be a step backward". I am not entirely convinced that there had been a step forward in the first place. Defining static construction order to be determined by the module import graph had been a half step forward. Completely disallowing static construction of circularly imported modules - a half step backward. The result is std.stdiobase and impossibility to initialize static data in mixins without resorting to lazy initialization. I can live with hacks like std.stdiobase when such are possible. What is more critical is initialization of mixins. Restating the problem: module a; mixin template Foo() { static immutable Object foo; shared static this() { foo = cast(immutable)new Object; } } ---- module b; import a; import c; mixin Foo; ---- module c; import a; import b; mixin Foo; In this scenario one is forced to avoid static constructors by lazily initializing foo and using some kind of synchronization, which should be absolutely unnecessary and sometimes is not tolerable. So which of the following is going to happen? 1. The current blinkered design will stay. 2. A solution will be provided before D2 is feature-freezed.Feature-frozen. Sorry.Note that I am well aware of http://yosefk.com/c++fqa/ctors.html#fqa-10.12 etc, but simply disallowing static construction is not a good solution for static construction problems.I'd really appreciate a reply from the language designers. What are the plans? 1. Static constructor semantics won't change. 2. We've worked out a solution and it will be implemented in a future compiler release. Please care to type 1 or 2. Thank you!
May 28 2010
Max Samukha Wrote:On 27.05.2010 13:37, Max Samukha wrote:Why has it become a tradition to ignore uncomfortable questions in these newsgroups?There was a discussion about those a while ago that terminated with Andrei's authoritative "it would be a step backward". I am not entirely convinced that there had been a step forward in the first place. Defining static construction order to be determined by the module import graph had been a half step forward. Completely disallowing static construction of circularly imported modules - a half step backward. The result is std.stdiobase and impossibility to initialize static data in mixins without resorting to lazy initialization. I can live with hacks like std.stdiobase when such are possible. What is more critical is initialization of mixins. Restating the problem: module a; mixin template Foo() { static immutable Object foo; shared static this() { foo = cast(immutable)new Object; } } ---- module b; import a; import c; mixin Foo; ---- module c; import a; import b; mixin Foo; In this scenario one is forced to avoid static constructors by lazily initializing foo and using some kind of synchronization, which should be absolutely unnecessary and sometimes is not tolerable. So which of the following is going to happen? 1. The current blinkered design will stay. 2. A solution will be provided before D2 is feature-freezed.Feature-frozen. Sorry.Note that I am well aware of http://yosefk.com/c++fqa/ctors.html#fqa-10.12 etc, but simply disallowing static construction is not a good solution for static construction problems.I'd really appreciate a reply from the language designers. What are the plans? 1. Static constructor semantics won't change. 2. We've worked out a solution and it will be implemented in a future compiler release. Please care to type 1 or 2. Thank you!
May 29 2010