Close Quietly (with no exception)

LMAX Exchange

A post about closing resources in Java. First though, an aside.

“Is it a good idea for destructors to throw?”

– Common C++ interview question

A quick bit of code can show us.

#include <iostream>
#include <stdexcept>

namespace {
  class Foo {
  public:
    void someUsage() {
      std::cout << "Using foo" << std::endl;
    }
    ~Foo() {
      std::cout << "Destroying foo" << std::endl;
      throw std::runtime_error("Exception 2");
    }
  };
}

int main() {
  std::cout << "Program started" << std::endl;
  try {
    Foo f;
    f.someUsage();
    throw std::runtime_error("Exception 1");
  } catch (std::exception const & e) {
    std::cout << "Caught exception!" << std::endl;
  }
  return 0;
}

Consider the above case where an object with a throwing destructor is popped from the stack. We naïvely hope our catch block will save us, but no, an exception has already thrown from another frame. We now have two exceptions to deal with and our program calls std::terminate (thanks to Alan for a correction here – I originally claimed this was UB).

Program started
Using foo
Destroying foo
terminate called after throwing an instance of 'std::runtime_error'
  what():  Exception 2
Aborted (core dumped)

This StackOverflow thread provides an excellent discussion of this issue from a C++ perspective. Many of the answers and comments gel nicely with the remaining content of this post, so it is well worth a read (but only once you’re done here, obviously).

What of our safe, garbage collected languages, though? What approach do we take to closing resources not managed by the VM?

If at first you don’t succeed…

try, catch, finally. This is the typical resource usage pattern in java – we acquire a resource (outside of the block – if we fail to acquire it, no close is required), use it in the try block, perform any desired exception handling in the catch block, and then clean up (usually invoking the close method on the object in question) in the finally block, which is (roughly) guaranteed to be called, regardless of what happens during try and catch.

Frequently the close method is marked as throwing a checked exception. This is annoying, as it means that even though we’ve performed some resource cleanup, our finally clause must also handle that exception type (or our function must propagate it upwards). Typically, we get around this by writing a closeQuietly method (or using one from an appropriate apache library) that catches the exception, suppresses it, then perhaps logs that a resource has failed to close.

This is absolutely fine for single resource usages – like reading all the data out of a file, or performing an http request to a remote server.

A more complicated world

Why’d you have to go and make things so complicated?

– Avril Lavigne

Commonly we will want to write applications that keep several resources of different species open for the lifetime of our application (or at least, considerably longer than a single function call). Perhaps a collection of sockets, some shared memory accessed through JNI and a sprinkling of semaphores.

What happens when we want to cleanly stop our application? These different resources will presumably be looked after by different pieces of our object graph, so we will have to traverse that graph calling close where appropriate.

In a perverse world, our code might look like this:

    public static void main(String[] args) {
        final SharedMemory memory = new SharedMemory();
        final CustomSocket customSocket = new CustomSocket();
        try {
            runApplication(memory, customSocket);
        } catch (Exception e) {
            e.printStackTrace(System.err);
        } finally {
            try {
                memory.close();
            } catch (SharedMemoryException e) {
                e.printStackTrace(System.err);
            }
            try {
                customSocket.close();
            } catch (SocketCloseException e) {
                e.printStackTrace(System.err);
            }
        }
    }

This may be a rather extreme example. Neither resource implements java.io.Closeable (which would make things easier as we could extract a single method), and both give feedback only in the form of a checked exception. I’ve left the try/catch blocks in place to illustrate just how annoying this is. How much worse this gets per different resource species is left as an exercise to the reader – one hopes it is obvious that this is another place that exception throwing fails to scale.

An alternative approach

We could mandate extension of Closeable for all such resources, but all this buys us is the ability to have just one static closeQuietly function. That would be a start. Can we do better though?

Groans from the crowd. Is this another anti-exception post? You bet it is. Let’s consider this alternative interface:

package net.digihippo;

import java.util.Collection;

public interface Closeable {
    public Collection<? extends Exception> close();
}

A couple of things to note here before we continue.

  • The interface isn’t actually that important – here’s the previous program with resources that follow this pattern without implementing the interface:
    public static void main(String[] args) {
        final SharedMemory memory = new SharedMemory();
        final CustomSocket customSocket = new CustomSocket();
        try {
            runApplication(memory, customSocket);
        } catch (Exception e) {
            e.printStackTrace(System.err);
        } finally {
            final List<Exception> closeProblems = new ArrayList<Exception>();
            closeProblems.addAll(memory.close());
            closeProblems.addAll(customSocket.close());
            for (final Exception e: closeProblems) {
                e.printStackTrace(System.err);
            }
        }
    }
  • Exception may not be the type that we want here. Once we have a return type, it’s possible that we just want a Collection of String messages that tell us why close has failed, rather than the considerably more expensive Exception. I chose it mostly because it was nearest, and possibly because having the stack could be useful for post-hoc rationalization.

These particular resources, in our example, share the program’s lifetime, and so the only customer for the close mechanism is the programmer trying to correctly order a whole bundle of unrelated shutdown and close calls. We will make their life a complete misery if we take the lazy option of failing to close by throwing – what on earth do we expect our shutdown writer to do with it?

Conclusion

For resource library creators

C++ has given us a good hint – throwing from close functions (and other functions in that family, like stop and shutdown) is unhelpful. In particular, throwing a custom checked exception type from a close method verges on malicious. It makes writing shutdown code tedious, and tedium is not a fate we should wish on anyone. We should do our brave shutdown hook writers a favour and provide our error output in a sanitized format. If we really, really must throw (and by goodness we need a superb excuse to do so), implementing java.io.Closeable is mandatory.

For shutdown writers

We are in a pretty poor place right now. From a brief scan of libraries I use, those pesky resource library creators (Presumably this includes the author? – Ed) have been out to get us – almost all of their close methods throw checked exception types that we have no hope of recovering from. Try to wrap their laziness as close to the source as possible; who knows, perhaps the idea will take off, and our lives infinitesimally improve.

Postscript

Having written no C++ for some time, I fashioned the top example without having to look up what header std::runtime_error was in, and the program compiled and ran at the first attempt. Get in. Admittedly, it didn’t do what I thought it would (my Foo was optimized away), but even that small victory made me smile. Having written this rather smug post-script I now eagerly await -Wpedantic like feedback from less rusty C++ writers!

Any opinions, news, research, analyses, prices or other information ("information") contained on this Blog, constitutes marketing communication and it has not been prepared in accordance with legal requirements designed to promote the independence of investment research. Further, the information contained within this Blog does not contain (and should not be construed as containing) investment advice or an investment recommendation, or an offer of, or solicitation for, a transaction in any financial instrument. LMAX Group has not verified the accuracy or basis-in-fact of any claim or statement made by any third parties as comments for every Blog entry.

LMAX Group will not accept liability for any loss or damage, including without limitation to, any loss of profit, which may arise directly or indirectly from use of or reliance on such information. No representation or warranty is given as to the accuracy or completeness of the above information. While the produced information was obtained from sources deemed to be reliable, LMAX Group does not provide any guarantees about the reliability of such sources. Consequently any person acting on it does so entirely at his or her own risk. It is not a place to slander, use unacceptable language or to promote LMAX Group or any other FX and CFD provider and any such postings, excessive or unjust comments and attacks will not be allowed and will be removed from the site immediately.