Thursday, June 7, 2012

Functional Programming with EasyJava

Functional programming with EasyJava

EasyJava is this idea I had, whereby, you make Java as easy as you can. It does not have Map literals or List literals, but with varargs, static imports, and some imagination You can get pretty close in size and expressivness. In the last blog bost I showed some examples of this. I've started with Python and just seeing what I can implement that is close in Java. My goal is less is more.

For this to make a lot of sense you need to see the previous post on this.

There is some Java boilerplate code, but we only have to do this once.

Get the class that will hold the "functions" for this

    Class <?> c = Example.class;

Python list comprehension

    print( dict([(x, x**2) for x in (2, 4, 6)]) )

Easy Java equivalent

    print ( dict(fn(c, "pow2"), list(2, 4, 6) ));

First thing to notice is that the Java version is about the same size as Python version, except that it is not because we have to define the function as follows.

pow2 "function"

static int pow2(int i) {
    return i * i;

The pow2 funciton is static because we are using this example code from main. If we were using pow2 from an instance method, then it could be defined as.

pow2 "function"

int pow2(int i) { return i * i; }

The you would use it as follows from within a instacne method.

Using fn with instance methods.

    print ( dict(fn(this, "pow2"), list(2, 4, 6) ));

The fn function is defined in EasyJava (Read first blog post).

    dict( fn(this, "pow2"), list(2, 4, 6) );

The first argument to dict is the function to apply to each member of the list. The sencond argume is the list. The funciton list, turns its arguments into a ArrayList<T> where T is the type of argument you past to list.

Output of Python list comprehension versus EasyJava equiv

    {2: 4, 4: 16, 6: 36}
    {2=4, 4=16, 6=36}

I've added a method called enumerate, which was inspired by Python's enumerate, but took a sharp 90 degree turn away.

Output of Python enumerate

    >>> for i, v in enumerate(['tic', 'tac', 'toe']):
        ...     print (i, v)
        0 tic
        1 tac
        2 toe

EasyJava enumerate takes a function

    enumerate(fn(c, s.printItem), list("tic", "tac", "toe"));

The enumerate takes a funciton which is created with a fn. The fn takes the a class (c), and a name (s.printItem). The name can be any object as fn just calls toString on it. This means you can use Java Enums as follows.

static enum s {printItem, cube, add};

This way if you use a function over and over, you don't have to worry about misspelling it, and you get code completiion.

The printItems is defined as follows:

static void printItem(int i, String v) {
    print(i , v);

Of course one could imagine it be defined like this:

void printItem(int i, String v) { print(i , v); }

The output of the Java version is as follows:

Output of enumerate example EasyJava

0 tic 
1 tac 
2 toe

The Java version is more verbose mostly due to the fact that there are no closures in Java yet. (There will be in Java 8.)

Python and EasyJava filter

Python filter

    def f(x): return x % 2 != 0 and x % 3 != 0
    print(filter(f, range(2, 25)))

Easy Java Filter

    class Filter { boolean f(int x) {
        return x % 2 != 0 && x % 3 != 0;
    print (filter(f(new Filter()), range(2, 25)));

The output is near identical. Notice the introduction of the f fucntion which is like fn, except is always looks for a method named f.

I also added a range function to EasyJava that is similar to Pythons.

Python map versus EasyJava map

Python map

    def cube(x): return x*x*x
    print( map(cube, range(1, 11)) )

Python map output

[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

EasyJava map

    static int cube(int x) { return x*x*x;}
    print (map(fn(c, s.cube), range(1,11)));

Java map output

[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]

Python reduce versus EasyMap reduce

Python reduce

def add(x,y): return x+y
print ( reduce(add, range(1, 11)) )

Python reduce output


EasyJava reduce

static int add(int x, int y) {return x + y;}
print ( reduce(fn(c,s.add), range(1,11)) );

EasyJava reduce output

Kafka and Cassandra support, training for AWS EC2 Cassandra 3.0 Training