Chapter 3. Migrating from FunctionalJ 0.7.x to 0.8

Table of Contents

3.1. Function interfaces
3.2. Type parameters (JDK 1.5 version)
3.3. Working with Functions
3.4. Working with tuples
3.5. Using reflection
3.6. Method differences
3.7. Using Collections instead of Lists

3.1. Function interfaces

In version 0.7.x, there was one Function base class and several subclasses. In version 0.8, function interfaces are used, and abstract base implementations are provided. Moreover, the interfaces provide stronger typing in that the interface indicates how many parameters are expected by the function. Instead of one general Function, there is Function0, Function1, Function2, Function3, Function4, and FunctionN (for an arbitrary number of parameters).

Instead of using function.addParameters(...).call(); to call a function, each interface defines a call() method that accepts the appropriate number of parameters to call the function directly. For instance, Function2 defines call(Object, Object) in the JDK 1.4 version, and call(P1, P2) in the JDK 1.5 version.

Recall that in version 0.7.x, the addParameters method returned a new Function object, achieving partial function application. In version 0.8, the method for binding parameters to a function has been renamed to bind. Each function interface defines a bind method that accepts a parameter and returns a function that accepts one less parameter. Thus, for example, the bind(Object) method in the Function3 interface returns a result of type Function2. Also, for functions that accept more than one parameter, there are additional bind methods for binding more than one parameter at a time.

New in version 0.8 is the possibility to bind a parameter at a different position than the default first position. To do so, you use a binding method that is named with the index of the position. For example, for binding the second parameter in a function that accepts three parameters, you would use the bind2 method.

3.2. Type parameters (JDK 1.5 version)

Also new in version 0.8 is a JDK 1.5 (or greater) version that uses type parameters. This makes it possible to declare the type of the result returned by a function, as well as the type of the parameters. When writing a method that uses a function, it is also convenient to be able to declare the type of function expected or returned by the method.

Here is a sample function definition:

// function that returns a Boolean, expects 2 parameters, of type Integer
// and String
Function2<Boolean,Integer,String> isLongerThan =
    new Function2Impl<Boolean,Integer,String>()
    {
        // The types below are in the same order as in the above declaration
        public Boolean call(Integer p_length, String p_string)
        {
            return p_string.length() > p_length;
        }
    };
Notice how using type parameters self-documents the function and removes the need to cast parameters. When calling the function, it also removes the need to cast the result.

3.3. Working with Functions

Since functions are more strongly typed in version 0.8 (by number of parameters in the JDK 1.4 version, and additionally by the types of the result and parameters in the JDK 1.5 version), the methods of the Functions class that accept a function as a parameter have been redefined to declare the function interface that corresponds to the appropriate number of parameters. In the JDK 1.5 version, this also includes the generic type parameters.

For example, the map method expects a function of 1 parameter and a collection of parameters, returning a list of results of calling the function on each parameter. In the JDK 1.4 version, this is declared as:

public static List map(Function1 p_function1, Collection p_coll);
In the JDK 1.5 version, this is declared as:
public static <R,P> List<R> map(Function1<R,P> p_function1,
    Collection<? extends P> p_coll);
Notice how the type parameters are used to indicate that the type of elements in the list of results match the type of the result returned by the function. Also, the type of the parameters in the list must be compatible with the type of the parameter expected by the function.

3.4. Working with tuples

For the JDK 1.5 version, tuples also use the type parameter feature. Thus you can declare the types of the objects contained by Pair, Triple and Quadruple. This also removes the need to cast the returned object when extracting it from the tuple. For example:

Pair<String,Integer> pair = new Pair<String,Integer>("A", 1);
String string = pair.getFirst();
Integer integer = pair.getSecond();
The methods of the Tuples class use this feature. For example, zipping two lists returns a list of typed pairs:
public static <A,B> List<Pair<A,B>> zip(Collection<A> p_coll1,
    Collection<B> p_coll2);

3.5. Using reflection

Version 0.7.x of FunctionalJ is primarily centered around using reflection to create functions that refer to constructors and methods. The reflection mechanism is implemented throughout ReflectionFunction and its subclasses.

In version 0.8, reflection is more clearly separated from the core of the library. Everything that concerns reflection is located in the reflect package and its subpackages. The core of the library has no dependence on reflection.

The reflection mechanism itself has also changed to using interfaces instead of having its implementation "hard-coded" into the library. This allows to use a different reflection mechanism if desired. Included in FunctionalJ are two implementations of the reflection mechanism: one that uses the JDK, and another that uses cglib.

New in version 0.8 is the choice between using dynamic reflection (much like what is used in version 0.7.x), or standard reflection. The main difference is that standard reflection requires the types of the parameters of the reflected constructor or method, while dynamic reflection does not. Why would you want to have to specify the types of the parameters? Because you may want the improved performance over the convenience of not having to specify the parameter types, or prefer to be more specific in your code about which constructor or method you are targetting.

3.6. Method differences

Between version 0.7.x and version 0.8, certain utility methods have changed:

  • Functions.concat becomes Strings.concat
  • Functions.intersperse becomes Strings.intersperse
  • Functions.sum has been removed
  • Lists.head becomes Lists.first

3.7. Using Collections instead of Lists

Throughout version 0.8, where appropriate, Collection is used instead of List in method parameters, allowing to use those methods with any type of Collection.