Menu

#6 Initialization order of package variables

closed-fixed
None
5
2004-03-05
2002-07-25
No

In one nice file put this:

var Hashtable<String, ()->Thing> factory = hashtable();

------------ in another put this:

var boolean thing_initialized = thing_initialize();
boolean thing_initialize() {
factory.put("p2pmud.Thing", int i => new Thing(id: i));
return true;
}

This will sometimes produce a null pointer exception, a
thing which should not be possible, since factory is
not of an optional type (and it violates the
no-null-poiner-exception claim of Nice;) ). To work
around it, I had to do use lazy initailization:

var boolean hasFactory = false;
var Hashtable<String, int->Thing> factoryTable;

boolean addHook(String className, int->Thing hook) {
if (!hasFactory) {
factoryTable = hashtable();
hasFactory = true;
}
factoryTable.put(className, hook);
return true;
}

---- The other file:

var boolean thing_initialized = thing_initialize();
boolean thing_initialize() = addHook("p2pmud.Thing",
(int i) => new Thing(id: i));

[noticed compiler bug when I tried to inline the
thing_initialized value -- I'll submit another bug
report for that one]

Static initialization issues have plagued us at least
since C++ made the problem popular. Perhaps there is a
solution to this problem. Would it be too hard to use
a dependency graph for thing_initialized to dertermine
that it depends on factory having a value initialized?

Discussion

  • Daniel Bonniot

    Daniel Bonniot - 2002-07-29
    • status: open --> open-later
     
  • Daniel Bonniot

    Daniel Bonniot - 2002-07-29

    Logged In: YES
    user_id=88952

    Yes, this is a problem. I think in Java this is handled by
    specifying strictly the evaluation order. It might be more
    tricky in Nice because global variables are not inside
    classes. There could be a partial order for variables in the
    same file...

    Yes, there could be a dependency analysis for simple cases.
    But in general you could call arbitraty code, that calls
    methods. The implementation of the method could be in a
    other package that is not yet known, and will make use of a
    variable of this package. So I think a global solution is
    not possible like that.

    For the moment, lazy initialization is a good idea. Or you
    could decide to put the factory and the addHook function in
    an object (a singleton), which would give the proper
    initialization order automatically.
    Actually what I would favor is that complex code like
    addHook(...) shoud be called from an explicit initialization
    function init()).

    I am open to suggestions to prevent this kind of problem
    automatically. It is indeed bothering to have
    NullPointerException from a type-safe program, although in a
    restricted area (static initialization).

    Daniel

    PS: with lazy initialization, you could use "if (factory ==
    nul)" and save the use of the boolean. However it is
    strange, since the type says factory cannot be null. A
    future version of the compiler might issue a warning or an
    error because of that.

     
  • Daniel Bonniot

    Daniel Bonniot - 2003-05-10
    • summary: vars unsafe (NullPointerException) --> Initialization order of package variables
     
  • Daniel Bonniot

    Daniel Bonniot - 2003-08-01

    Logged In: YES
    user_id=88952

    There has been some progress in this domain recently. The
    global values used to be initialized in a somewhat
    unpredictable order, causing problems as reported here when
    one global depended on another. A recent change in the
    compiler (present in the development version, future 0.9.1)
    now guarantees much more properties:

    1) if the value of a global g1 references another one g2,
    then g2 will be initialized before g1 (provided there is no
    cycle of course).
    2) if g2 occurs after g1 in the same file, and neither is
    referenced by another global, then g1 is initialized before g2.

    This solves a lot of situations already. What is not handled
    yet is "hidden references" though a method call (which
    happens in your example, so I won't close this report). It
    might be possible to extend the analysis for these cases,
    although it is more complex. So I keep an eye on this issue.

     
  • Daniel Bonniot

    Daniel Bonniot - 2004-03-05
    • status: open-later --> closed-fixed
     
  • Daniel Bonniot

    Daniel Bonniot - 2004-03-05

    Logged In: YES
    user_id=88952

    I just implemented a more thourough handling of dependencies
    between packages variables. Now both direct references and
    indirect depency through the default implementation of a
    method are considered. This second case in particular covers
    the original case in this report.

    This system can still fail, notably if the dependency comes
    from a specialization of the a called method. It would be
    more difficult to handle that, especially as that
    specialization could be made in another package (this would
    rarely affect the initialization of the current package if
    we don't import that other one, but still might, at least
    when using reflexion). The current implementation still
    covers safely much more situations than before, so it's a
    good step ahead. I think it's fair to now close this report,
    which hopefully will hold the longevity record for a long
    time ;-)

    (BTW, Bill, how are you doing? :-)

     
  • Daniel Bonniot

    Daniel Bonniot - 2004-03-05
    • assigned_to: nobody --> bonniot
     

Log in to post a comment.