Friday, September 2, 2011

Multiple Return Values in Java


Multiple Return Values in Java
posted by Bjorn Raupach 
IconToday was one of those days when I wished Java would support multiple return values. I had to develop a rather CPU-intensive algorithm which would compute a solution for a knotty constraint problem. Having a solution alone is sometimes not enough and you also need to add some parameters which measure the quality of the computed outcome. Most of these accompanying parameters can or have to be computed within the algorithm itself, but Java allows you to return only one value either an object or a primitive type. People working with Lisp, MATLAB or Perl, just to mention a few, don't have a problem like this at all. Functions supporting multiple return values is already implemented at the language level and frameworks make heavy use of this. But as a Java programmer you are pretty much stuck here and need to consider some other means to come out of this situation. In the following I would like to give some hints on that topic. Hopefully they are of help for anyone having the same problem every now and then.One very pragmatic solution is claiming to integrate this into the upcoming Java releases. Since Java is open source there is a good chance of a bunch of programmers gathering to implement this. We have had generics, annotations and Java 7 will even support closures. In fact it looks like with closures you can simulate having the ability to return more than one value. So why not add the functionality of multiple return values in, say, Java 8? It wouldn't add too much semantic sugar. Well, even so I like the way the language evolves -- it just gives Java an increased feeling of beingbloated. Annotations are a good example for this. Great if you work, for example, with EJB but besides that I scarcely ever use them. Shouldn't a programming language contain only the things you need for your daily task? Don't get me wrong, if multiple return values ever make it into the Java specs I will be happy to use them, but if I would be the one to decide, I would leave them out.
Ok, lets assume you don't want to wait and have a solution right know. Since a method can only return a single object this has to be our wrapper for accessing the different return values. Some people might now claim: "Hey, but then I have to create another object. This is a waste in terms of performance." I won't go into further detail about that. Java is object-oriented! If you are afraid of creating single objects then you shouldn't use Java at all. Events are fired through Objects and many things more. So really there is nothing wrong with creating objects on a very frequent basis. javax.vecmath.Tuple3b is a good example for a simple Wrapper. It contains just three bytes and all it takes is just a single line: return new Tuple3b(aByte, bByte, cByte);
A better objection to dislike wrapper objects is the increase in lines of code that need to be written. The more you code the harder it is to read for others and for yourself in the future. This is a good point. Lets investigate what we can do about this. Take the following class for example. It acts as a wrapper for two objects:
public class TwoReturnValues {
 
 private Object first;
 private Object second;
 
 public TwoReturnValues(Object first, Object second) {
  this.first = first;
  this.second = second;
 }
 
 public Object getFirst() {
  return first;
 }
 
 public Object getSecond() {
  return second;
 }
}
A perfect object-oriented approach for having a wrapper around two objects. And since Java 1.5 supports autoboxing we don't have to give primitive types a special treatment, right? Well, this will really result in writing ugly code. Lets say some arbitrary methods needs to return a String s and an int n. No problem just write: return new TwoReturnValues(s,n);
For the callee it gets more cumbersome. Both getFirst and getSecond return java.lang.Object. Though the callee knows about the real types, he has to cast first to String and second to int. This is ugly and it is common knowledge that casts spread around your code should be avoided. Lets make things easier and add generics:
public class TwoReturnValues {
 
 private R first;
 private S second;
 
 public TwoReturnValues(R first, S second) {
  this.first = first;
  this.second = second;
 }
 
 public R getFirst() {
  return first;
 }
 
 public S getSecond() {
  return second;
 }
}
Changing the signature of the method to TwoReturnValues >String,Integer< we not only got rid of those casts, but the code looks much more straightforward. One could argue that Generics itself are bloated fixings, but like I said if it is already in the language go ahead and use it. Wether or not the two accessore methods are needed in this specific case is open to dispute. Since this Object has no other purpose as to deliver values we can ignore encapsulation at least a bid and make first and second public. However then you should declare both fields final as well and regard the whole Object as immutable! This gives you also the advantage of having a thread-safe object (unless the fields itself are mutable).
public final class TwoReturnValues {
 
 public final R first;
 public final S second;
 
 public TwoReturnValues(R first, S second) {
  this.first = first;
  this.second = second;
 }
 
 public R getFirst() {
  return first;
 }
 
 public S getSecond() {
  return second;
 }
}
The shown approach can easily be broadened to support more than two return values. As long as the callee knows how many objects he has to return and the number won't exceed lets say 2-4 you will be fine with this solution. And a line like (i,j,r,s,t,u,v,w) = foo() will doubtless convince not anybody to vote for supporting multiple return values in Java.
Finally consider the case mentioned in the last paragraph. Lets say a method returns an unknown, but big number of values. Unfortunately here you really need to write many more lines of code to retrieve and convert all the data. Those who have worked with ResultSet and JDBC before know what I am talking about. An intermediate procedure would be returning an array of Objects, albeit you will end up using casts again if all the elements in the array have different types. But I believe even returning some kind of collection is better than adding support for multiple return statements.

0 comments: