Stanley M. Ho wrote:
Hi Bryan,

Bryan Atsatt wrote:
Um, I'm not arguing about the restriction in custom import policies, I
certainly understand why that is present.

I'm saying that an initializer *should* be able to rely on imported
modules, so we need a separate mechanism. And that separate mechanism
would kick in *after* resolution/validation had completed.

And yes, there is potentially a pathological case even here, if two
initializers have cyclic dependencies (not the Class kind ;^), but...
Seems to me that this has to be discovered and eliminated in
development; this is a variation on the "order of static initialization"
problem, and one that we can't solve here.

I think we agreed that in the presence of circular dependencies a module
cannot rely on its initializer being called before other code in the
module is called. The problem is that a module may not know if it is
part of a cyclic dependency chain because that depends on its imports,
their imports, etc. I don't think we can assume that this is a
pathological case that never occurs in the real world.

Sure, it *can* happen, just like <clinit> execution order between
classes can cause problems.

But we still have class initializers in the language; I don't see this
any differently. In the unusual case where a problem does occur, it must
be fixed by refactoring the code in some fashion. So what? How can this
be an argument that class initializers shouldn't exist?

Sorry, Stanley, but I just don't buy this argument.

It is also unclear to me if providing the release() method would be
useful outside a container environment as well. As I hinted before, you
probably want to do the clean up in the finalizer or something similar
when nobody uses the module instance anymore, rather than when the
module instance is released from the module system while other existing
users could still access it.

ARGH! Stanley, we've been going around in circles on this for years now
:^). Yes, the lifecycle problem is made visible more often in container
environments, but it is not limited to them: if this spec is going to
enable a module to be released during the life of a process, then we've
just pulled the problem directly into SE, container or no container.

Your argument here is that since we cannot know whether a module's
classes are in use *after* it has been released/uninstalled, informing
the module that it has been released is pointless, since it cannot do
anything meaningful.

This is utter nonsense (sorry)! If a module requires some kind of
initialization (whether we make it easy or not), it almost certainly
needs to cleanup at some point. In your view, the way to accomplish such
cleanup is during GC. In the real world, this is rarely sufficient: a
single class leak (often caused by JRE classes!) will cause it to fail.
And, often worse, the timing issue rears its ugly head: another
module/class comes up that needs to acquire the same resources. This is
then a race condition over which you have little control. GC is not the
answer to all resource management.

Proper resource management requires a well-defined lifecycle: threads,
server sockets, client sockets, files, file locks, native library
resources, external (server) resources, etc. all need to be explicitly
managed.

We need to at least give modules a well-defined time to release
resources (and a module should be free to reject calls into it after
those resources have been released).

Either we should avoid this problem entirely by eliminating the ability
to release modules, OR we should provide a means to solve the problem.
Clearly, I am strongly in favor of the latter. And the solution should
be symmetrical...

It seems irresponsible in the extreme for this EG to waste the
opportunity to introduce a standardized lifecycle, with both init and
release calls to the module itself.

// Bryan

BTW: In the ModuleInitializer I suggested, I would provide no-op
implementations for all the methods. If you don't care about
getImports(), for example, you shouldn't have to do anything in your
subclass.

Reply via email to