Showing posts with label generics. Show all posts
Showing posts with label generics. Show all posts

Wednesday, July 19, 2006

Test Driving Interface Usage

One of the neat things (or drawbacks) with Generics in Java is that the left hand side of an assignment can't always be treated separately to the right hand side because of type inferencing.

A simple example is Collections.emptySet(). By itself it will produce an empty set of Objects. If the left hand side defines a Set of Integers (or you use a cast) then that's what it will return.

Unexpectedly, this makes it possible to enforce an interface on the left hand side of an assignment without using something like Checkstyle or other ways of enforcing coding conventions.

The answer seems to be to create a generic object factory which wraps using reflection to create an object. The simplest API would be something like:
<T> T create(Class<T> concreteClass, Object... values).

To create an empty ArrayList and an ArrayList with a default capacity of 255 you would write:
List list = creator.create(ArrayList.class);
List list = creator.create(ArrayList.class, 255);

This allows you to create expectations such that a call to create must return an interface. Using EasyMock test code is something like (from memory):
List list = createMock(List.class);
creator.create(ArrayList.class);
creatorControl.andReturn(list);

The following creates an exception as it causes the wrong type to be created (an ArrayList not a List):
ArrayList list = creator.create(ArrayList.class)

When the API is this simple it can become quite difficult to work out which constructor should be called. The simplest, at least initially, is to fail when there are multiple constructors of the same length or to create a more complicated API where you specify the constructor types. You could also have more complicated behaviour like calling the most specific constructor, where there are multiple matches for the given objects, could create a more sophisticated version. Starting with the constructor arguments and matching against the objects seems like a quicker implementation than trying to match the objects against the constructors.

Tuesday, June 27, 2006

Revisiting Visitor

I was looking for another approach to implement parsing expressions and came across Visitors in JSR 269 and "The Expression Problem Revisited", "The expression problem (aka the extensibility problem) refers to a fundamental dilemma of programming: Can your application be structured in such a way that both the data model and the set of virtual operations over it can be extended without the need to modify existing code, without the need for code repetition and without runtime type errors."

"All proposals that we know of take as a starting point either a data-centered approach, making it hard to add new operations, or an operation-centered (visitor-based) approach, making it equally hard to add new data types."

"Despite its simplicity, this trick is one of the major contributions of this paper, because it finally moves the visitor-based approach to the expression problem into the realm of static type safety...[it] divides the node classes of the different phases into separate, incompatible families, each characterized, in the form of a type parameter, by the specific brand of Visitor they are capable of accepting."

To put it another way, this enables you to define what implementation of Visitor you wish to use when you construct your visitable classes (at compile time, not runtime) - a pretty neat trick.

Via, why Visitors?.

Update: I've started using these ideas in JRDF to implement the SPARQL query layer and see what practical benefits are.

Wednesday, June 14, 2006

Test Driving Java 5

I was wrong that you can't test drive generic types in Java. There is a getGenericType and getDeclaredAnnotations. More information, "Reflecting generics". It is a pain though with the methods returning an interface that has to be cast up and the implementations live in the sun.* package.