Alexandre Martins’ Blog

On software & technology

Archive for the ‘Functional Programming’ tag

Hamcrest Out Of Test Code!

with 7 comments

It’s been a while since I read some interesting posts showing creative uses of Hamcrest library out of test code. Since then I’ve been proscrastinating to implement my own version, trying strongly typed java delegates.

Thankfully this week I came across a nice API called hamcrest-collections. It uses Hamcrest to implement features such as select, reject, map, reduce and zip familiar from languages like Ruby and Python.

Selectors

Selectors can be used to select or reject items that matches a given Matcher, from any iterable object. It reminds me the Specification Pattern from Domain-Driven Design, which is also used for querying objects that satisfies defined specifications.

public static final Person john = new Person("John", 28);
public static final Person nicole = new Person("Nicole", 12);
public static final Person ryan = new Person("Ryan", 23);
public static final Person nathan = new Person("Nathan", 18);

public static final List list() {
    return Arrays.asList(john, nicole, ryan, nathan);
}



The code below selects from the list of users defined above, the ones that are under twenty.

@Test
public void should_select_only_people_under_twenty_years_old() {
    List users = Person.list();
    Iterable underTwentyList = select(users, underAge(20));
    assertThat(underTwentyList, hasItems(nicole, nathan));
    assertThat(underTwentyList, not(hasItems(john, ryan)));
}



The code below rejects all the users that are under twenty.

@Test
public void should_reject_every_people_under_twenty_years_old() {
    List users = Person.list();
    Iterable aboveTwentyList = reject(users, underAge(20));
    assertThat(aboveTwentyList, hasItems(john, ryan));
    assertThat(aboveTwentyList, not(hasItems(nicole, nathan)));
}


Map and Reduce

Map is used to apply a function onto each item in any iterable object, whereas Reduce combines all these elements, applying a Reducer implementation. In our example, we map the timesTwo function, that doubles each element in the list, and then we reduce it by adding up all of them.

@Test
public void should_double_each_number_in_the_list_then_sum_all_of_them() {
    List numbers = Arrays.asList(1, 2, 3);
    MultiplyBy timesTwo = new MultiplyBy(2);

    Iterable result = map(numbers, timesTwo);
    assertThat(result, hasItems(2, 4, 6));

    Integer sum = reduce(result, new Sum());
    assertThat(sum, equalTo(12));
}


public class MultiplyBy implements Function {
    private Integer factor;

    public MultiplyBy(Integer factor) {
        this.factor = factor;
    }

    public Integer apply(Integer number) {
        return (int)number * factor;
    }
}


public class Sum implements Reducer {
    public Integer apply(Integer first, Integer second) {
        return first + second;
    }
}


Despite the bias created by some developers, that Hamcrest should not be used anywhere else but test code, specially after JUnit has defined it as its new matcher library, just ignore it and add these features to your runtime library, so that you can let your creativity drive you when developing. Get rid of “for” loops from your life! :)

Written by Alexandre Martins

February 19th, 2009 at 6:38 am

Clojure: Integrating With Java

with 3 comments

Currently I am learning Clojure. It is a functional programming language, but not a pure one, since you can both write code that share state (mutable) and also ones that doesn’t.

Why Clojure?

The main reason why I chose Clojure is its easy interoperability with Java, still one of the most used languages, bringing to it the power of Lisp. It’s fast, since the code is compiled, and it supplements some of Java’s weakness, such as the Collections framework and concurrent programming. It is pretty straightforward to write concurrent programs, everything is automatic, no manual lock management!

Integrating With Java

Importing classes

A single class:

(import java.util.List)

Multiple classes from the same package:

(import '(java.util List Set))

Creating instances

Using Java’s new keyword:

(new java.util.ArrayList)
(new ArrayList) ; after importing

Assigning a new List to a Clojure variable:

(def list (new java.util.List))
-> #'user/list

Syntactic Sugar:

(ArrayList.)

Accessing fields

Static fields:

(. Math PI)

Syntactic Sugar:

Math/PI

Invoking methods

Static Methods

(.currentTimeMillis System)

Syntactic Sugar:

(System/currentTimeMillis)

Non-static Methods

(. list size)
(. list get 0) ; returns the object stored at index 0

Syntactic Sugar:

(.size list)

Mixing Them All

Clojure provides a macro called memfn that makes possible execute Java methods as functions. So, for a list of String objects, if I want to make all of them upper-case, all I have to do is:

(map (memfn toUpperCase) ["a" "short" "message"])

The map function applies the function/method toUpperCase to each element in ["a" "short" "message"]

You can also use the bean function to wrap a Java bean in an immutable Clojure map.

(bean (new Person "Alexandre" "Martins"))
-> {:firstName "Alexandre", :lastName "Martins"}

Once converted, you can manipulate the new map using any of Clojure’s map functions, like:

(:firstName (bean (new Person "Alexandre" "Martins")))
-> Alexandre

The code above extracts the firstName key, originally from the Person object.

Written by Alexandre Martins

January 1st, 2009 at 12:44 am