Thursday, May 22, 2008

Nothing's guaranteed

Kasper B. Graversen's blog entry on 'Exception handling problems in Java' came up in my news reader today, courtesy of dzone. He wants to be able to extract common exception handling code from catch clauses into methods, allowing reusability of that code, and removing clutter from the main logic.

Here's a silly example, replete with dubious practices for the sake of conciseness :)

Food makeLunch() {

try {
return kitchen.makeSandwich();
}
catch (KitchenClosedException ex) {
handleException(ex, "Couldn't make a sandwich :(");
}
catch (NoBreadException ex) {
handleException(ex, "Couldn't make a sandwich :(");
}
return null;
}

void handleException(Exception ex, String message) throws RuntimeException {
log.error("Something went wrong", ex);
throw new RuntimeException(message, ex);
}


Kasper points out that the 'return null;' statement at the end of the makeLunch() method is pointless - although we can see that it will never be executed, the compiler requires it because the signature of the handleException() method only says that it may throw an exception, but does not guarantee it.

There's some discussion of the 'problem' here, including alternative ways to structure the code.

With the BGGA closures prototype though, we can rewrite the example as follows:

Sandwich makeLunch() {

try {
return kitchen.makeSandwich();
}
catch (KitchenClosedException | NoBreadException ex) {
handleException(ex, "Couldn't make a sandwich :(");
}
}

Nothing handleException(Exception ex, String message) throws RuntimeException {
log.error("Something went wrong", ex);
throw new RuntimeException(message, ex);
}

There are three changes to the original example here:
  • BGGA allows us to catch multiple types of exception with one catch clause.

  • The signature of the handleException() method now has a return type of java.lang.Nothing, which guarantees that the method will not 'complete normally' (because it always throws an exception). The compiler can enforce this guarantee, and we can take advantage of it:

  • Because of the above change, the 'return null;' is neither required, nor allowed, since the compiler now knows that the statement can never be executed.


Which is nice.

6 comments:

Paul said...

Nothing is the most unintuitive -- can I say "stupid"? -- programming language concept I've ever seen. I'd like someone to convince me that there is a difference between null and nothing in common everyday language. Imagine if databases had these two concepts! LOL Thanks for the grief, Neal.

Adam J. Conover said...
This comment has been removed by the author.
Adam J. Conover said...

I can't I really say I like the idea of a "Nothing" data-type either, but I think it is clearly different from null. "Null" means that there is an actual data type but with no value (where it otherwise might have one), whereas the "Nothing" would mean (at least in the given syntax) that an object of type "Nothing" is being returned. I assume, the "Nothing" data-type would be an empty interface, and hence, not even have the possibly of possessing a "value" in any real sense.

To me, I think this is more easily confused with "void". What would be the difference (in practice) between returning an object of type "Nothing" vs. returning no object (void)?

Though I think that even the possibility of returning null is a bad idea... if the sandwich could not be made, then the exception should propagate up to the caller (or a new exception be thrown). I'm definitely in the camp that thinks that null is never a reasonable return value. But... it was stated that "dubious practices" were employed. :)

(Ps. sorry for the deleted post above...)

Konstantin Triger said...

I like the idea - I do want the compiler to verify my 'throwing only' method. My critics is related to implementation:

1. In fact the method does not return 'Nothing', it does not return at all. So letting it to return a special type does not reflect reality, but only makes the compiler happy.

2. Sometimes I need to ensure that some method override always throws (due to my design of the derived class). In this case the signature cannot be changed and I cannot use a new feature...

The solution is an annotation, like "@AlwaysThrows", which will pass a required hint to the compiler.

Paul said...

I do not think using Nothing or an annotation is appropriate to say the method must always throw an exception. That to me smells of extending the Java language through unrelated constructs.

If that syntax must exist -- and I must admit the notion that a method must ALWAYS throw an exception is appealing -- then I think the language should update its syntax.

Dropping out the return value would be nice:

handleException(Exception ex, String message) throws RuntimeException;

Andrei Navodnik said...

I don't see the point of using class Nothing if the same problem could be solved with existing Java as follows:

Food makeLunch() {
  try {
    return kitchen.makeSandwich();
  } catch (KitchenClosedException ex) {
    throw handleException(ex,
    "Couldn't make a sandwich :(");

  } catch (NoBreadException ex) {
    throw handleException(ex,
    "Couldn't make a sandwich :(");
  }
}

RuntimeException handleException(
    Exception ex, String message) {
  log.error("Something went wrong", ex);
  return new RuntimeException(message, ex);
}

The pattern that consists of combination of keyword throw and method that returns an exception (in bold print) actually guarantees that the exception is ALWAYS thrown, so I don't see the reason to include in Java another type which "partialy mirrors" funcionality of type Void. The class Nothing is needed to properly implement closures and function types, but should this class be public and part of java.lang package?

I'm curious, what are other planned usages of class Nothing?