July 24, 2006

Closures for refactoring

Comments about my previous article reminded me (in an indirect sort of way) of another "programming in the small" thing - using closures for refactoring.

Closures - good for collections

Fans of languages with closures often show collection processing sorts of things - like most of the examples in one of Martin Fowler's articles that I showed python translations for, and python's alternative to this sort of thing - called "list comprehensions". However, closures also allow for some neat refactorings independent of anything to do with collections.

Duplication that looks difficult to get rid of

Let's say you've been working with David and Ade and you've produced the definitive way of reading a byte from a file. Later you find you need to read a UTF encoded string from a file. You use the same "pattern" (in a loose sense of the word) in both cases.
	int readByteFromFile(String fileName) throws IOException {
		InputStream inputStream = new FileInputStream(fileName);
		try {
			return inputStream.read();
		} finally {
			try {
				inputStream.close();
			} catch (IOException ex) {
				log("Hi Ade.");
			}
		}
	}
	
	String readStringFromFile(String fileName) throws IOException {
		InputStream inputStream = new FileInputStream(fileName);
		try {
			DataInputStream dataInput = new DataInputStream(inputStream);
			return dataInput.readUTF();
		} finally {
			try {
				inputStream.close();
			} catch (IOException ex) {
				log("Hi Ade.");
			}
		}
	}
You don't want to have to keep repeating this every time you want to do something similar, but slightly different. How do you refactor the similarities between these methods? The fact is that in Java I see lots of this sort of duplication - because in Java, getting rid of this sort of duplication is often verbose and clunky. However, it is possible, and sometimes very worthwhile.

Using closures to get rid of the duplication

Java provides a way to define some sort of closures - using anonymous inner classes. Here's how you could remove the duplication in this example. It's quite painful. My fingers hurt as I typed the code. Then I got a headache.
	interface DoWithFile {
		Object execute(FileInputStream inputStream) throws IOException;
	}

	public Object withFile(String fileName, DoWithFile runThis) throws IOException {
		FileInputStream inputStream = new FileInputStream(fileName);
		try {
			return runThis.execute(inputStream);
		} finally {
			try {
				inputStream.close();
			} catch (IOException ex) {
				DuplicatedCode.log("Hi Ade.");
			}
		}
	}

	int readByteFromFile(String fileName) throws IOException {
		return ((Integer) withFile(fileName,
				new DoWithFile() {
					public Object execute(FileInputStream inputStream)
							throws IOException {
						return inputStream.read();
					}
				})).intValue();
	}

	String readStringFromFile(String fileName) throws IOException {
		return (String) withFile(fileName, new DoWithFile() {
			public Object execute(FileInputStream inputStream)
					throws IOException {
				DataInputStream dataInput = new DataInputStream(inputStream);
				return dataInput.readUTF();
			}
		});
	}
Despite how horrible this looks - it is sometimes worth it.

... and in Python

In languages with better support for closures (or at least support for passing functions around), it can look a whole lot better. A direct translation of the original code in Python (taking the liberty of defining a class DataInputStream) would be:
def readByteFromFile(fileName):
	inputStream = file(fileName)
	try:
		return inputStream.read(1)
	finally:
		try:
			inputStream.close()
		except:
			log("Hi Ade.")

def readStringFromFile(fileName):
	inputStream = file(fileName)
	try:
		dataInput = DataInputStream(inputStream)
		return dataInput.readUTF()
	finally:
		try:
			inputStream.close()
		except:
			log("Hi Ade.")
Passing a function as a parameter (as a closure) gives:
def withFile(fileName, function):
	inputStream = file(fileName)
	try:
		return function(inputStream)
	finally:
		try:
			inputStream.close()
		except:
			log("Hi Ade.")

def readByteFromFile(fileName):
	def execute(inputStream):
		return inputStream.read(1)
	return withFile(fileName, execute)

def readStringFromFile(fileName):
	def execute(inputStream):
		dataInput = DataInputStream(inputStream)
		return dataInput.readUTF()
	return withFile(fileName, execute)
which hurts much less than the Java version (but slightly more than the Smalltalk version would - but that's another story). [Martin Fowler shows in his article how a Ruby caller of similar code would look "File.open(filename) {|f| doSomethingWithFile(f)}".] Python doesn't have great syntax for defining closures - it would be nice to be able to define the two "execute" functions anonymously. You can do this for one of the methods using "lambda" but not the other because of the limitations of "lambda". In Smalltalk or Ruby the syntax for this is better. Here's the "lambda" version of the "readByteFromFile" function.
def readByteFromFile(fileName):
	return withFile(fileName, lambda inputStream: inputStream.read(1))

I'll tell you what I want, what I really, really want, because David wants to know.

I'd like Java to have better support for closures. I'm impressed with C#'s anonymous delegates, although, it's still not as good as Smalltalk. I'd also like developers to put more effort into reducing duplication, even when the language gets in the way.
Posted by ivan at 9:09 PM Copyright (c) 2004-2007 Ivan Moore | Comments (3)

July 18, 2006

Programming in the small - finally.

Following on from the previous article in the series, there are some "programming in the small" style things that I don't see as often as I'd expect.

"Non-structured programming" - using finally

Consider the following (Java) code:

	int readValue() throws IOException {
		InputStream file = new FileInputStream("temp.txt");
		int result;
		try {
			result = file.read();
		} finally {
			file.close();
		}
		return result;
	}

This can be written slightly shorter, and I think slightly better:

	int readValue() throws IOException {
		InputStream file = new FileInputStream("temp.txt");
		try {
			return file.read();
		} finally {
			file.close();
		}
	}

However, I hardly ever see other people using this style. This way of using finally came up when writing a previous article with Bjorn Freeman-Benson - he likes this style too. I don't expect to see this style all the time - just a lot more than I do, which is hardly ever.

Comments:

Comments aren't working at the moment, but here's one by email from David Peterson (and he's right, you know. I've altered the code as David's suggestion - I originally had the code working but a bit wrong due to "brain fart"). (David's "I got rejected (blacklisted)" applies to everyone at the moment).

Hi Ivan,

It's better not to put the creation of the stream within the try.. finally. If the constructor throws an exception then you will end up calling close() on a null reference.

So, an even shorter (and safer) version is...

    int readValue() throws IOException {
        InputStream stream = new FileInputStream("temp.txt");
        try {
            return stream.read();
        } finally {
            stream.close();
        }
    }

David

P.S. I tried posting a comment, but I got rejected (blacklisted). :-(

Another comment, from Adewale Oshineye:

There's a reason people don't write methods like the one in your
example. The IOException that's thrown can be misleading. The call to
read() can throw an exception which then gets buried if the call to
close() also throws an exception.

The smallest safe version of that method looks something like:

int readValue() throws IOException {
       InputStream inputStream = new FileInputStream("temp.txt");
       try {
               return inputStream.read();
       } finally {
               try {
                       inputStream.close();
               } catch (IOException e) {
                       //we can't do anything about this except log it
                       LOG.warn("Problem closing inputStream", e);
               }
       }
}

My response: Thanks for the comment - I should have picked a better example - catching the possible IOException from the close is unrelated to the point of having a return inside a try finally and some code you want to execute after the return and my example has detracted from that point.

Posted by ivan at 8:39 PM Copyright (c) 2004-2007 Ivan Moore | Comments (2)