Thread overview | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
September 02, 2004 Module init ordering bug - analysis and code example | ||||
---|---|---|---|---|
| ||||
Walter, in learning how D handles module constructors, I came across the same bug that others have stumbled across. I did a little sleuthing to discover what was causing this problem. ;) My analysis (see below) showed that modules without constructors (static this(){}) cannot be prioritized in _moduleCtor(), nor will their imports be prioritized, since without such a constructor a module isnt't added to the _moduleinfo_array. Is this correct? If so (and if you don't mind), I'd like to propose that dmd be changed to add all modules (not just those with ctors) to the _moduleinfo_array. This would not only fix these particular init problems, but would also be very useful for reflection purposes. Many, many thanks, Eric [Example] The expected init order was: mod4, mod3, mod2, mod1 as that is the order of import and the order of dependency by function call. Instead the modules are run in a different order: mod2, mod1, mod4. Inserting a module constructor into mod3 forces the correct init order. //// mod1.d //// import std.stdio; import std.moduleinit; import mod2; static this(){ writefln("mod1"); } void main(){ writefln("\n--MODULE INFO--\n"); foreach(ModuleInfo info; _moduleinfo_array){ writefln("%s", info.name); foreach(ModuleInfo imported; info.importedModules){ writefln("\timport %s",imported.name); } } } //// mod2.d //// import std.stdio; import mod3; static this(){ writefln("mod2"); mod3.foo(); } //// mod3.d //// import std.stdio; import mod4; /* Uncomment to force correct ordering static this(){ writefln("mod3"); } */ static void foo(){ writefln("\tmod3.foo()"); mod4.bar(); } //// mod4.d //// import std.stdio; static this(){ writefln("mod4"); } static void bar(){ writefln("\tmod4.bar()"); } //// Output //// mod2 mod3.foo() mod4.bar() mod1 mod4 --MODULE INFO-- mod1 import mod2 mod2 mod4 format utf string adi import string gcbits import string thread - Pragma [[ EricAnderton at (static this{}) yahoo dot com ]] |
September 02, 2004 Re: Module init ordering bug - analysis and code example - mod.zip | ||||
---|---|---|---|---|
| ||||
Posted in reply to pragma Attachments: | Update: The problem gets worse with 'private import'. Module ctor dependencies seem to only be added if the 'private' declaration is dropped, regardless of the presence of a module ctor. An revised version of my example (with private imports used) is attached. The output shows that mod1 no longer shows a dependency upon mod2. mod1 mod2 mod3.foo() mod4.bar() mod4 --MODULE INFO-- mod1 mod2 mod4 format utf string adi import string gcbits import string thread -Pragma In article <ch7s0p$mi8$1@digitaldaemon.com>, pragma says... > >Walter, >in learning how D handles module constructors, I came across the same bug that >others have stumbled across. I did a little sleuthing to discover what was >causing this problem. ;) > >My analysis (see below) showed that modules without constructors (static >this(){}) cannot be prioritized in _moduleCtor(), nor will their imports be >prioritized, since without such a constructor a module isnt't added to the >_moduleinfo_array. Is this correct? > >If so (and if you don't mind), I'd like to propose that dmd be changed to add all modules (not just those with ctors) to the _moduleinfo_array. This would not only fix these particular init problems, but would also be very useful for reflection purposes. > >Many, many thanks, >Eric > > > >[Example] >The expected init order was: mod4, mod3, mod2, mod1 as that is the order of >import and the order of dependency by function call. Instead the modules are >run in a different order: mod2, mod1, mod4. Inserting a module constructor into >mod3 forces the correct init order. > >//// mod1.d //// >import std.stdio; >import std.moduleinit; >import mod2; > >static this(){ >writefln("mod1"); >} > >void main(){ >writefln("\n--MODULE INFO--\n"); > >foreach(ModuleInfo info; _moduleinfo_array){ >writefln("%s", info.name); >foreach(ModuleInfo imported; info.importedModules){ >writefln("\timport %s",imported.name); >} >} >} > > >//// mod2.d //// >import std.stdio; >import mod3; > >static this(){ >writefln("mod2"); >mod3.foo(); >} > > >//// mod3.d //// >import std.stdio; >import mod4; > >/* Uncomment to force correct ordering >static this(){ >writefln("mod3"); >} >*/ > >static void foo(){ >writefln("\tmod3.foo()"); >mod4.bar(); >} > > >//// mod4.d //// >import std.stdio; > >static this(){ >writefln("mod4"); >} > >static void bar(){ >writefln("\tmod4.bar()"); >} > > >//// Output //// >mod2 >mod3.foo() >mod4.bar() >mod1 >mod4 > >--MODULE INFO-- > >mod1 >import mod2 >mod2 >mod4 >format >utf >string >adi >import string >gcbits >import string >thread > >- Pragma >[[ EricAnderton at (static this{}) yahoo dot com ]] |
September 02, 2004 Re: Module init ordering bug - analysis and code example - mod.zip | ||||
---|---|---|---|---|
| ||||
Posted in reply to pragma | Yep; I just posted you a reply on dsource. The issue is with the importedModules[], which is supposed to house a list of imported modules (filtered to include only those which require static initialization) ~ per-module. Unfortunately, if you add /any/ kind of attribute to an import statement, it is excluded from importedModules[]. Entire chains of dependency are thus lost, and static constructors are never executed. Anything project that (for example) makes use "private import" is thus inviting doom. "pragma" <pragma_member@pathlink.com> wrote in message news:ch84ft$r1b$1@digitaldaemon.com... Update: The problem gets worse with 'private import'. Module ctor dependencies seem to only be added if the 'private' declaration is dropped, regardless of the presence of a module ctor. An revised version of my example (with private imports used) is attached. The output shows that mod1 no longer shows a dependency upon mod2. mod1 mod2 mod3.foo() mod4.bar() mod4 --MODULE INFO-- mod1 mod2 mod4 format utf string adi import string gcbits import string thread -Pragma In article <ch7s0p$mi8$1@digitaldaemon.com>, pragma says... > >Walter, >in learning how D handles module constructors, I came across the same bug that >others have stumbled across. I did a little sleuthing to discover what was causing this problem. ;) > >My analysis (see below) showed that modules without constructors (static >this(){}) cannot be prioritized in _moduleCtor(), nor will their imports be >prioritized, since without such a constructor a module isnt't added to the >_moduleinfo_array. Is this correct? > >If so (and if you don't mind), I'd like to propose that dmd be changed to add >all modules (not just those with ctors) to the _moduleinfo_array. This would >not only fix these particular init problems, but would also be very useful for >reflection purposes. > >Many, many thanks, >Eric > > > >[Example] >The expected init order was: mod4, mod3, mod2, mod1 as that is the order of >import and the order of dependency by function call. Instead the modules are >run in a different order: mod2, mod1, mod4. Inserting a module constructor into >mod3 forces the correct init order. > >//// mod1.d //// >import std.stdio; >import std.moduleinit; >import mod2; > >static this(){ >writefln("mod1"); >} > >void main(){ >writefln("\n--MODULE INFO--\n"); > >foreach(ModuleInfo info; _moduleinfo_array){ >writefln("%s", info.name); >foreach(ModuleInfo imported; info.importedModules){ >writefln("\timport %s",imported.name); >} >} >} > > >//// mod2.d //// >import std.stdio; >import mod3; > >static this(){ >writefln("mod2"); >mod3.foo(); >} > > >//// mod3.d //// >import std.stdio; >import mod4; > >/* Uncomment to force correct ordering >static this(){ >writefln("mod3"); >} >*/ > >static void foo(){ >writefln("\tmod3.foo()"); >mod4.bar(); >} > > >//// mod4.d //// >import std.stdio; > >static this(){ >writefln("mod4"); >} > >static void bar(){ >writefln("\tmod4.bar()"); >} > > >//// Output //// >mod2 >mod3.foo() >mod4.bar() >mod1 >mod4 > >--MODULE INFO-- > >mod1 >import mod2 >mod2 >mod4 >format >utf >string >adi >import string >gcbits >import string >thread > >- Pragma >[[ EricAnderton at (static this{}) yahoo dot com ]] |
September 02, 2004 Re: Module init ordering bug - analysis and code example | ||||
---|---|---|---|---|
| ||||
Posted in reply to pragma | D's only requirement for ordering module constructors between modules is that the imported module constructors must happen first. They are not ordered by the order of the import statements - or at least such order is an artifact of the implementation. You should therefore be able to control the order of module construction by making sure that each module depending on another module constructor imports that module. "pragma" <pragma_member@pathlink.com> wrote in message news:ch7s0p$mi8$1@digitaldaemon.com... > Walter, > in learning how D handles module constructors, I came across the same bug that > others have stumbled across. I did a little sleuthing to discover what was > causing this problem. ;) > > My analysis (see below) showed that modules without constructors (static > this(){}) cannot be prioritized in _moduleCtor(), nor will their imports be > prioritized, since without such a constructor a module isnt't added to the _moduleinfo_array. Is this correct? > > If so (and if you don't mind), I'd like to propose that dmd be changed to add > all modules (not just those with ctors) to the _moduleinfo_array. This would > not only fix these particular init problems, but would also be very useful for > reflection purposes. > > Many, many thanks, > Eric > > > > [Example] > The expected init order was: mod4, mod3, mod2, mod1 as that is the order of > import and the order of dependency by function call. Instead the modules are > run in a different order: mod2, mod1, mod4. Inserting a module constructor into > mod3 forces the correct init order. > > //// mod1.d //// > import std.stdio; > import std.moduleinit; > import mod2; > > static this(){ > writefln("mod1"); > } > > void main(){ > writefln("\n--MODULE INFO--\n"); > > foreach(ModuleInfo info; _moduleinfo_array){ > writefln("%s", info.name); > foreach(ModuleInfo imported; info.importedModules){ > writefln("\timport %s",imported.name); > } > } > } > > > //// mod2.d //// > import std.stdio; > import mod3; > > static this(){ > writefln("mod2"); > mod3.foo(); > } > > > //// mod3.d //// > import std.stdio; > import mod4; > > /* Uncomment to force correct ordering > static this(){ > writefln("mod3"); > } > */ > > static void foo(){ > writefln("\tmod3.foo()"); > mod4.bar(); > } > > > //// mod4.d //// > import std.stdio; > > static this(){ > writefln("mod4"); > } > > static void bar(){ > writefln("\tmod4.bar()"); > } > > > //// Output //// > mod2 > mod3.foo() > mod4.bar() > mod1 > mod4 > > --MODULE INFO-- > > mod1 > import mod2 > mod2 > mod4 > format > utf > string > adi > import string > gcbits > import string > thread > > - Pragma > [[ EricAnderton at (static this{}) yahoo dot com ]] |
September 02, 2004 Re: Module init ordering bug - analysis and code example - mod.zip | ||||
---|---|---|---|---|
| ||||
Posted in reply to pragma | "pragma" <pragma_member@pathlink.com> wrote in message news:ch84ft$r1b$1@digitaldaemon.com... > Update: > The problem gets worse with 'private import'. Module ctor dependencies seem to > only be added if the 'private' declaration is dropped, regardless of the presence of a module ctor. I'm glad you were able to track this down. Now I can fix it! |
September 03, 2004 Re: Module init ordering bug - analysis and code example | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | So are you saying the supplied example isn't a bug? How about something like
mod1.m:
module mod1;
import mod2;
static this() { mod2.run(); }
mod2.m:
module mod2;
import mod3;
void run() { mod3.run(); }
mod3.m:
module mod3;
void* never_null;
static this() { never_null = new int; }
void run(){ printf("is never_null null? %p eek!\n",never_null); }
I would think this problem makes module initialization very easy to get around. How about a default (trivial) module constructor gets generated for a module if any of its imported modules have a constructor.
Walter wrote:
> D's only requirement for ordering module constructors between modules is that the imported module constructors must happen first. They are not ordered by the order of the import statements - or at least such order is an artifact of the implementation.
>
> You should therefore be able to control the order of module construction by making sure that each module depending on another module constructor imports that module.
>
> "pragma" <pragma_member@pathlink.com> wrote in message news:ch7s0p$mi8$1@digitaldaemon.com...
>> Walter,
>> in learning how D handles module constructors, I came across the same bug
> that
>> others have stumbled across. I did a little sleuthing to discover what
> was
>> causing this problem. ;)
>>
>> My analysis (see below) showed that modules without constructors (static
>> this(){}) cannot be prioritized in _moduleCtor(), nor will their imports
> be
>> prioritized, since without such a constructor a module isnt't added to
>> the
>> _moduleinfo_array. Is this correct?
>>
>> If so (and if you don't mind), I'd like to propose that dmd be changed to
> add
>> all modules (not just those with ctors) to the _moduleinfo_array. This
> would
>> not only fix these particular init problems, but would also be very useful
> for
>> reflection purposes.
>>
>> Many, many thanks,
>> Eric
>>
>>
>>
>> [Example]
>> The expected init order was: mod4, mod3, mod2, mod1 as that is the order
> of
>> import and the order of dependency by function call. Instead the modules
> are
>> run in a different order: mod2, mod1, mod4. Inserting a module
> constructor into
>> mod3 forces the correct init order.
>>
>> //// mod1.d ////
>> import std.stdio;
>> import std.moduleinit;
>> import mod2;
>>
>> static this(){
>> writefln("mod1");
>> }
>>
>> void main(){
>> writefln("\n--MODULE INFO--\n");
>>
>> foreach(ModuleInfo info; _moduleinfo_array){
>> writefln("%s", info.name);
>> foreach(ModuleInfo imported; info.importedModules){
>> writefln("\timport %s",imported.name);
>> }
>> }
>> }
>>
>>
>> //// mod2.d ////
>> import std.stdio;
>> import mod3;
>>
>> static this(){
>> writefln("mod2");
>> mod3.foo();
>> }
>>
>>
>> //// mod3.d ////
>> import std.stdio;
>> import mod4;
>>
>> /* Uncomment to force correct ordering
>> static this(){
>> writefln("mod3");
>> }
>> */
>>
>> static void foo(){
>> writefln("\tmod3.foo()");
>> mod4.bar();
>> }
>>
>>
>> //// mod4.d ////
>> import std.stdio;
>>
>> static this(){
>> writefln("mod4");
>> }
>>
>> static void bar(){
>> writefln("\tmod4.bar()");
>> }
>>
>>
>> //// Output ////
>> mod2
>> mod3.foo()
>> mod4.bar()
>> mod1
>> mod4
>>
>> --MODULE INFO--
>>
>> mod1
>> import mod2
>> mod2
>> mod4
>> format
>> utf
>> string
>> adi
>> import string
>> gcbits
>> import string
>> thread
>>
>> - Pragma
>> [[ EricAnderton at (static this{}) yahoo dot com ]]
|
September 03, 2004 Re: Module init ordering bug - analysis and code example | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | In article <ch8c1i$tdd$1@digitaldaemon.com>, Walter says... > >D's only requirement for ordering module constructors between modules is that the imported module constructors must happen first. They are not ordered by the order of the import statements - or at least such order is an artifact of the implementation. > >You should therefore be able to control the order of module construction by making sure that each module depending on another module constructor imports that module. Gotcha. Thank you for confirming this, as that's pretty much where all my hacking lead me. (Actually it was pretty much in plain D for everyone in moduleinit.d, but that's another story) :) However, the order of operations really isn't so crucial since it visits all the dependencies recursively, and flags everything on the way out to keep from running things more than once. (its a good compact design!) We also now know what conditions dmd pays attention to (at least in 0.101) when adding nodes to this constructor list. As to the problem at hand: I feel that having dmd add all modules to the list (rather than just those with ctors) will be a huge improvement to the language. Thanks Walter! - Pragma [[ Eric Anderton at (_moduleCtor) yahoo dot com ]] |
September 07, 2004 Re: Module init ordering bug - analysis and code example | ||||
---|---|---|---|---|
| ||||
Posted in reply to pragma | "pragma" <pragma_member@pathlink.com> wrote in message news:ch8fa0$ujm$1@digitaldaemon.com... > As to the problem at hand: I feel that having dmd add all modules to the list > (rather than just those with ctors) will be a huge improvement to the language. The problem with that is that then two modules could not import each other. |
September 08, 2004 Re: Module init ordering bug - analysis and code example | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter | In article <chjl73$259k$1@digitaldaemon.com>, Walter says... > > >"pragma" <pragma_member@pathlink.com> wrote in message news:ch8fa0$ujm$1@digitaldaemon.com... >> As to the problem at hand: I feel that having dmd add all modules to the >list >> (rather than just those with ctors) will be a huge improvement to the >language. > >The problem with that is that then two modules could not import each other. Would this be only if both modules have static ctors, just one, or none at all? I would think that the latter two cases would never be a problem given the way moduleinit.d is already coded: it's already assuming that there are modules in the list w/o ctors as it is checking for that condition (lines 111 and 121). Just put modules on the list with null ctors/dtors if none are declared and it should work fine (IMO). And you already know the first case is already being handled quite nicely. :) Or have I missed the point completely and there is some other case that's causing a problem? - Pragma [[Eric Anderton at yahoo dot com]] |
September 10, 2004 Re: Module init ordering bug - analysis and code example | ||||
---|---|---|---|---|
| ||||
Posted in reply to pragma | "pragma" <pragma_member@pathlink.com> wrote in message news:chn51k$r3a$1@digitaldaemon.com... > In article <chjl73$259k$1@digitaldaemon.com>, Walter says... > > > > > >"pragma" <pragma_member@pathlink.com> wrote in message news:ch8fa0$ujm$1@digitaldaemon.com... > >> As to the problem at hand: I feel that having dmd add all modules to the > >list > >> (rather than just those with ctors) will be a huge improvement to the > >language. > > > >The problem with that is that then two modules could not import each other. > > Would this be only if both modules have static ctors, just one, or none at all? > > I would think that the latter two cases would never be a problem given the way > moduleinit.d is already coded: it's already assuming that there are modules in > the list w/o ctors as it is checking for that condition (lines 111 and 121). > Just put modules on the list with null ctors/dtors if none are declared and it > should work fine (IMO). > > And you already know the first case is already being handled quite nicely. :) > > Or have I missed the point completely and there is some other case that's causing a problem? The problem is if A imports B, and B imports A, whose initialization code gets run first? The imports imply a dependency, so we have "A requires that B's initializers run first" coupled with "B requires that A's initializers run first." There's no resolution. The only one I can think of is that a module with no initializers doesn't have a requirement that the imports get initialized first. And I think that is always correct - that if there *is* such a dependency in the code, then there's something else wrong. |
Copyright © 1999-2021 by the D Language Foundation