Destructors in Java

Sep 2, 2004
Last updated: March 23, 2005
For comments: tzvetanmi@yahoo.com

Recently I have been thinking about destructors in Java. On the surface, there is all this controversy with finalizers and the unpredictability of the garbage collector. However, there is really no reason that "destructing" an object has to be coupled with deallocating its memory. If "destructing" the object is independant of its deallocation, the object will continue to exist after it has been destructed, as long as it is still reachable, but will be no more than an empty shell. Presumably the its methods will check that the object has been destructed and fail.

For objects that need actual cleanup (e.g. files, graphics resources in SWT, other native resources), it is usually clear when the cleanup has to happen; very often (if not most of the time) the useful lifetime of an object is tied to its lexical scope - either a method or an owning object. Java could easily be extended to use this and provide facility very close in spirit to C++ destructors.

First of all, a new interface Destructable should be added:

interface Destructable
{
  void destruct ();
};

Every "destructable" object must implement this interface. This is, of course, very similar to C#. Further, we introduce a new modifier "own", which signifies that the referenced object (which must implement Destructable) is "owned" and must be destructed as soon as execution leaves its lexical scope, or when the owning object itself is destructed.

Here are a couple of examples to make things clearer. In the first example, the file will be closed at the exit of the method, much like it would be in C++:

void method () {
  own java.io.FileInputStream input = new java.io.FileInputStream( "file.txt" );
  doSomething( input );
}

The compiler will generate something like this:

void method () {
  java.io.FileInputStream input = new java.io.FileInputStream( "file.txt" );
  try {
    doSomething( input );
  }
  finally  {
    input.destruct();
  }
}

Obviously this is much more powerful than C#'s "using" keyword, which can easily be emulated with this syntax.

In the second example, the lexical scope of the reference is its owning object:

class MyClass {
  private own java.io.FileInputStream input = new java.io.FileInputStream( "file.txt" );
}

Behind the scenes the compiler will implement the "Destructable" interface for MyClass and automatically generate its destruct() method, resulting in something like this:

class MyClass implements Destructable {
  private java.io.FileInputStream input = new java.io.FileInputStream( "file.txt" );
  public void destruct () {
    input.destruct();
  }
}

So, whenever MyClass itself is destructed, it will auto-destruct its "input" member.

There are a couple more details to be worked out:

In conclusion, this seems like a very easy addition to the language. Backward compatibility is preserved. I see no problems with it at all. I think it could relatively easily be added to an existing compiler (and perhaps I will).

--- March 23, 2005

After some research, it seems that the Polyglot Extensible Compiler Framework might allow me to do exactly what I want very easily.

It is a framework which allows easy implementations of additions to the Java language. The additions are implemented with grammar inheritence and AST manipulation. The output is standard Java which can then be compiled with any Java compiler.

One of the examples of Polyglot usage trivially adds automatic boxing and unboxing to Java. I would say that is very impressive.

The open question is how robust Polyglot's Java parser is. Is it really applicable to production code ? To answer that I ran one of my projects through it and the results are mostly encouraging. Polyglot choked a couple of times, but I was able to rectify that by trivial modifications to my sources (for example splitting complex expressions). It is still in active development, so I am hoping it will continue to improve.

Back to my home page