Sunday, April 27, 2008

Static methods as function objects

In one of the earlier posts I described a policy object created by "functional style programming" in Java. The basic idea is to make methods into Function and Predicate objects and then composite the logic from these building blocks. The problem though was that the policy implementation looked alien to Java. To re-cap: I wanted to invoke a different function based on the class of the object - classical multi-dispatch with a single argument.

So inspired by extension methods idea I added a new mechanism to define properties (and functions in general) - via static methods. You define a bunch of static methods with the same name (or appropriately annotated) like this:

static int size(Collection c) {
return c.size();
}
static int size(Map map) {
return map.size();
}
static int size(Object obj) {
return (obj.getClass().isArray() ?
Array.getLength(obj) : 1);
}
Now assuming I have a property declaration
Property<Object,Integer> size =
new Property<Object,Integer>(0) {};
The underlying implementation of the size.of(object) would be a "policy" (composite function) dispatching to one of the static methods according to run-time type of the object. So that size.of("foo") is 1, size.of(Arrays.asList("a","b","c")) is 3 and size.of(null) is 0.

There are couple of issues though.

Issue #1: automatically ordering the rules. Now when rules are not added manually, I should be careful to test for more specific class first. The solution is to calculate a distance between two classes and always look for a best match - basically same algorithm javac uses when choosing methods at compile-time. This isn't fully unambiguous though: if class C implements 2 interfaces A and B, having different implementations of size(A) and size(B) would put me into a dilemma which one to choose for size(C). Javac in such a case reports an error - thanks to Java being statically typed. But once I make it a run-time decision the only logical solution is to report an error at run-time. To make the problem less acute, I could add an annotation that controls ordering of the methods.

Issue #2: this is less generic than a general predicate-based policy - it is limited to "instanceof" predicate. One of the policies I use internally in the properties project is reflectively invoke getFoo() if the class has a "getFoo" method. This isn't possible with static methods.

Issue #3: reflection. It's not really a problem, but rather an enhancement I want to make: instead of using reflection I could generate the functions at compile-time with APT, like Bruce Chapman does here. This is one of my next adventures, which I will hopefully describe in a future post.

2 comments:

Anonymous said...

Hi
Great article. This would be really nice to have on JavaLobby.
If you're interested in reposting, please contact me at james at dzone dot com.

Regards
James

custom term paper said...

As I think it is intended to let application developers "write once, run anywhere." Java is currently one of the most popular programming languages in use, particularly for client-server web applications