4

I'm wondering if there is a good way of explicitly declaring (not necessarily enforcing) ownership transfer of resources in Java.

My problem is basically this: There are resources that need to be cleaned up (think AutoClosable) that are dependency-injected into an instance by its creator. I want to communicate to the creator that the instance takes full ownership over, and responsibility for, said resource (at source level, since I am pretty sure there is no way to enforce that in Java).

I am currently entertaining the idea of using a wrapper class Owned<T>, that basically behaves like an Optional that always needs to be filled.

Is this worthwhile? Should I just put a comment in the JavaDoc? Or is there a common way this is handled?

Kolja
  • 233

2 Answers2

5

I think it should be possible to implement this using @Owned annotations for function parameters and return types. Whoever calls new initially owns a resource. If you own a resource, you must either destroy it or give it away – either by returning it as an @Owned resource or passing it to a function that claims ownership of it. After you've given up ownership, you must not use the resource any more. If you got passed a resource as a parameter not annotated as @Owned, you must not destroy it and must not pass it to functions that would claim ownership of it. To define “destruction”, we'd probably want a @Destroys annotation for methods on a resource.

The idea is basically taken from Rust (disclaimer: I have never actually programmed in Rust) which itself I believe is strongly inspired by C++. I think that the annotation system in Java should be strong enough to hook in a static analyzer that would enforce the correctness of your program with zero run-time overhead. Since I have never written a static analyzer plugin for the Java compiler, I have no idea how difficult / easy that would be. A more practical problem you'd have to overcome is that many standard and third-party library functions will not care about your annotations and you'd need to figure out some mechanism to inform your analyzer that you know what you are doing. (Such as “unsafe” @Owned T makeOwned(T t) and T makeNotOwned(@Owned T t) methods that “cast away” the annotation. Or support for an external annotations file to load annotations for third-party intrefaces from.)

I think that this would be a very interesting academic project but fear that it would almost certainly turn into a giant time sink if applied to any practical project.

5gon12eder
  • 7,236
2

I am not sure there is a common way this is handled, because it takes a lot of work and discipline to do it right, and most people would rather leave open the possibility of error than discipline themselves.

I like to experiment, especially with ways of reducing the possibility of error, so from time to time I have been using various techniques.

One technique is the "hand-off" pattern: whenever a closeable resource is passed from object A to object B, a "handOff" boolean flag is also passed, telling object B whether it should dispose of the resource when it is done with it. I am not terribly satisfied with it, because it is not enforceable at all: the holder of the resource may do the exact opposite of what the "handOff" parameter suggests.

Another technique which is halfway enforceable is using the type system to its fullest extent: if you are given a disposable resource, you must always dispose it. If you are not going to dispose it, then it should not be disposable. In other words, if it is not disposable, then you cannot dispose it.

Unfortunately, the JRE has not been designed with this in mind, so you have to redo a lot of classes and interfaces for it to work. For example, InputStream is a class which implements Closeable. So, if you were to use the type system technique with this class as it is, it would mean that whenever you would pass an InputStream to someone you would have to kiss it bye-bye.

So, classes like InputStream would have to be reworked as follows:

An InputStreamResource class is introduced, fully encapsulating the original InputStream class of the JRE; A new InputStream interface is introduced, containing all the methods of the original InputStream class, except Close(); then, InputStreamResource is made to implement the new InputStream interface, and the Closeable interface. Thus, anyone accepting an InputStreamResource promises to close it, while anyone accepting an InputStream interface is simply unable to close it, because it is not Closeable.

Mike Nakis
  • 32,803