views:

113

answers:

4

Is something like this possible to do in Java?

for (Object o : objects) {
  for (Function f : functions) {
    f(o);
  }
}

I'm only calling a handful of functions, but I need to compose them, like so:

for (Object o : objects) {
  for (Function f : functions) {
    for (Function g : functions) {
      f(g(o));
    }
  }
}

And I'd like to avoid writing out hundreds of lines of function calls.

I've tried researching function pointers and functors, but haven't found anything pertinent.

+5  A: 

You can't use the f(g(o)) syntax, but you can use (with a suitable interface) f.call(g.call(o)).

public interface UnaryFunction<Arg, Ret> {
    Ret call(Arg arg);
}

Example usage (this is as close as you can get to functors in Java, at least until closures make it into the language):

public class Exp implements UnaryFunction<Double, Double> {
    public Double call(Double arg) {
        return Math.exp(arg);
    }
}


If you don't want to create a zillion classes, a reflection-based approach may work better (example for double -> double functions in java.lang.Math, but easily adaptable to other scenarios):

public class MathUnary implements UnaryFunction<Double, Double> {
    private final Method method;

    public MathUnary(String funName) {
        try {
            method = Math.class.getMethod(funName, double.class);
        } catch (NoSuchMethodException exc) {
            throw new IllegalArgumentException(exc);
        }
        if (method.getReturnType() != double.class)
            throw new IllegalArgumentException();
    }

    public Double call(Double arg) {
        try {
            return (Double) method.invoke(null, arg);
        } catch (IllegalAccessException exc) {
            throw new AssertionError(exc);
        } catch (InvocationTargetException exc) {
            throw new AssertionError(exc);
        }
    }
}

(Exception messages have been left out for brevity. Obviously, I'd put them in for production code.)

Sample usage:

MathUnary[] ops = {
    new MathUnary("sin"), new MathUnary("cos"), new MathUnary("tan")
};

for (UnaryFunction<Double, Double> op1 : ops) {
    for (UnaryFunction<Double, Double> op2 : ops) {
        op1.call(op2.call(arg));
    }
}
Chris Jester-Young
The FunctionalJava library (http://functionaljava.org/) already piece-meals together a bunch of wrapper classes (a set of generic classes with varying type-arity in this case) for this sort of scenario.
pst
Wow. Functional Java was obviously designed with code golfing (or obfuscation :-P) in mind...package name `fj`, with functor type `F`, with method named `f`. I like the idea behind the library, but I'd not have chosen those names. :-P
Chris Jester-Young
A: 

Maybe you can try a fluent interface that would let you gang these together. It might be a nice design, but I can't tell from your example.

duffymo
The function composed in the inner loops is called on the object from the outer loop: f(g(o))
antonm
Oops, missed the argument. Sorry.
duffymo
A: 

Java doesn't really do functors exactly, but you can get pretty close with an interface. I'd reccommend maybe trying something like this.

public interface Function {
    Object doWork(Object o);
}

public class Function1 implements Function {
    public Object doWork(Object o) {
        ...
    }
}

...

And then in your code you'd create an array or list containing Function1, Function2 ... objects and run something that looks a lot like your code.

for (Object o : objects) {
      for (Function f : functionList) {
          f.doWork(o);
      }
}

Or, for two levels of nesting:

for (Object o : objects) {
      for (Function f : functionList1) {
            for (Function g : functionList2) {
                f.doWork(g.doWork(o));
            }
      }
}
Seth
Not a fan of generics?
Chris Jester-Young
Generics certainly work (no question there). But would you have a little bit more flexibility at runtime if everything was an Object? For a solution with Generics like the one above with the Doubles, you'd essentially have to have your return value for g always match the argument to f. For plain old Objects, f's logic can be different based on the return type of g.
Seth
A: 

@Seth -- Here is your example with generics. Since generics don't exist at runtime, I do not understand why you fear a loss of "flexibility". If you use generics, then you are just using Objects.

If you want F's behavior to vary based on the return type of G, then you would just declare your F to do something like F, easy peasy.

//=== Function.java

public interface Function<ReturnType, Type> {
    ReturnType doWork(Type arg);
}

//=== SomethingWeird.java

import java.util.*;

// yo dawg, i heard you liked functions.  so i put a function in yo'
// function, so you can derive while you derive.
public class SomethingWeird {
    public static <FReturnType, FType, GType> List<FReturnType> collateOrSomething(
        Iterable<GType> objects,
        Iterable<Function<FReturnType, FType>> fList,
        Iterable<Function<FType, GType>> gList
    ) {
        List<FReturnType> results = new ArrayList<FReturnType>();
        for (GType garg : objects) {
            for (Function<FReturnType, FType> f : fList) {
                for (Function<FType, GType> g : gList) {
                    results.add(f.doWork(g.doWork(garg)));
                }
            }
        }
        return results;
    }
}

//=== SomethingWeirdTest.java

import java.util.*;

import org.junit.*;
import static org.junit.Assert.*;

public class SomethingWeirdTest {
    // this is kinda silly, and...
    public static class F1 implements Function<Integer, Double> {
        @Override
        public Integer doWork(Double arg) {
            return arg.intValue();
        }

    }

    // ...this has all kinds of autoboxing madness, but...
    public static class F2 implements Function<Integer, Double> {
        @Override
        public Integer doWork(Double arg) {
            double ceil = Math.ceil(arg);
            return (int) ceil;
        }       
    }


    // ...why you'd want to do something like this is quite beyond me...
    public static class G1 implements Function<Double, String> {
        @Override
        public Double doWork(String arg) {
            return Math.PI * arg.length();
        }
    }

    // ...ditto this...
    public static class G2 implements Function<Double, String> {
        @Override
        public Double doWork(String arg) {
            return Math.E * arg.length();
        }

    }

    // oh, yeah, it was so we could test this weird thing
    @Test
    public void testCollateOrSomething() {
        List<String> data = Arrays.asList("x", "xx", "xxx");
        List<Function<Integer, Double>> fList = Arrays.asList(new F1(), new F2());
        List<Function<Double, String>> gList = Arrays.asList(new G1(), new G2());
        List<Integer> results = SomethingWeird.collateOrSomething(data, fList, gList);

        assertEquals(12, results.size());

        // x
        assertEquals(3, (int) results.get(0));
        assertEquals(2, (int) results.get(1));
        assertEquals(4, (int) results.get(2));
        assertEquals(3, (int) results.get(3));

        // xx
        assertEquals(6, (int) results.get(4));
        assertEquals(5, (int) results.get(5));
        assertEquals(7, (int) results.get(6));
        assertEquals(6, (int) results.get(7));

        // xxx
        assertEquals(9, (int) results.get(8));
        assertEquals(8, (int) results.get(9));
        assertEquals(10, (int) results.get(10));
        assertEquals(9, (int) results.get(11));
    }
}
Charles