Skip to main content

Closures and Multiple Return Values

Posted by brucechapman on November 28, 2007 at 8:00 PM PST

In javaposse 150 the guys were talking about something and veered off on a tangent talking about multiple return values and tuples and such like. Next up they talked about the closures JSR. That sparked a thought that maybe we could transform the multiple return values problem in order to solve it using closures.

So what if instead of returning multiple values, a method returned void, but had another formal parameter which was a closure to receive the results of the method?

I've downloaded the closures prototype compiler (2007-11-20 version) and had a play with that idea. Now if it had been a complete disaster you wouldn't be reading this, because I wouldn't have blogged about it, but you are reading it so lets get on with it.

Here is a method to convert rectangular to polar coordinates and pass the results (r,theta) to a receiver closure.

    static void toPolar(double x, double y, {double, double => void } rThetaReceiver) {
        rThetaReceiver.invoke(Math.sqrt(x*x + y*y), Math.atan2(y, x));
    }

And this is how you use it

        // test toPolar
        toPolar(3,4,{double r, double theta =>
            System.out.format("3,4 = %f<%fRad%n",r,theta);
        });

Here is the complete class with both converters, and a round trip test. Note how the round trip nests the closures.

package closures.multireturn;

/**
*
* @author bchapman
*/
public class RectangularToPolar {
   
    static void toPolar(double x, double y, {double, double => void } rThetaReceiver) {
        rThetaReceiver.invoke(Math.sqrt(x*x + y*y), Math.atan2(y, x));
    }
   
    static void toRectangular(double r, double theta, { double, double => void} xYReceiver) {
        xYReceiver.invoke(r * Math.cos(theta), r * Math.sin(theta));
    }

    public static void main(String[] args) {
       
        // test toPolar
        toPolar(3,4,{double r, double theta =>
            System.out.format("3,4 = %f<%fRad%n",r,theta);
        });
       
        // test toRectangular
        toRectangular(5, Math.PI / 2, { double x, double y =>
                System.out.format("5<90deg = %f,%f%n",x,y);
        });

        // test Round trip - toPolar and back to rectangular
        toPolar(3,4,{double r, double theta =>
            System.out.format("3,4 = %f<%fRad%n",r,theta);
            toRectangular(r, theta, { double x, double y =>
                System.out.format("%f<%fRad = %f,%f%n",r,theta,x,y);
            });
        });
    }
}

And here's the output

C:\projects\quickhacks\src>javac closures\multireturn\RectangularToPolar.java

C:\projects\quickhacks\src>java closures.multireturn.RectangularToPolar
3,4 = 5.000000<0.927295Rad
5<90deg = 0.000000,5.000000
3,4 = 5.000000<0.927295Rad
5.000000<0.927295Rad = 3.000000,4.000000

This looks promising. I'll keep exploring.

One of the interesting things which I think this demonstrates is how closures are such a fundamental building block that they offer the potential of solving quite a few other problems that we've traditionally thought of as requiring specialist language changes. Maybe such solutions are not quite as nice as a specialist language change, but good enough that the advantage of not having yet another language feature outweighs the now small disadvantage of not having the perfect solution.

Related Topics >>