Tuesday, September 15, 2009

How would Linq look like in Java

After thinking a while about Linq for Java I started to experiment. My main driver was to find out how Linq would look like in Java. I started with a simple task: From a given range of floats convert ever item to an integer and take those that are less or equal four. In C# this would look like this:

IEnumerable<float> source =
   
new []{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

IEnumerable<int> result =
   
source.Select(x=>(int)x).Where(x=> x<= 4);

Java has neither delegates nor any lambda syntax, so statements like x=>x<=4 are not possible. So I decided to model the delegates as interfaces:

public interface UnaryFunction<Arg, Result> { 
    Result execute(Arg arg);
}

Linq statements basically are so called extension methods to the IEnumerable<T> and/or IQueryable<T> interface. The Java equivalent is the Iterable<T> interface. However, there is nothing like an extension method in java, so I had to fall back on the OO way of extension: inheritance.

public interface Queryable<T> extends Iterable<T>{
   <U> Queryable<U> select(UnaryFunction<T, U> select); 
   Queryable<T> where(UnaryFunction<T, Boolean> pred);
}

So if every operation returns a new Queryable<T> object, it would be possible to chain the calls very similar to the C# way.

This looked very promising! I decided that the real work should be done on the Iterator<T> level and implemented specific iterators for the select and where operations. Here is the SelectIterator as an example:

class SelectIterator<From, To> implements Iterator<To> {

   
private final Iterator<From> inner;
    private final UnaryFunction<From, To> select;

    SelectIterator(Iterator<From> inner,
                          UnaryFunction<From, To> sel) {
        this.inner = inner;
        this.select = sel;
    }
    public boolean hasNext() {
        return inner.hasNext();
    } 
    public To next() {
        return select.execute(inner.next());
    } 
    public void remove() {
        throw new UnsupportedOperationException("");
    }
}

I implemented the Queryable<T> interface with an abstract base class and concrete anonymous inner classes:

abstract class QueryableImpl<T> implements Queryable<T> {  
   <U> Queryable<U> select(final UnaryFunction<T, U> s){
        return new QueryableImpl<U>(){
            @Override
            public Iterator<U> iterator() {
                return new SelectIterator(
                       QueryableImpl.this.iterator(), s
                                        
);
            }
        };
    }

    // … and some more
    public abstract Iterator<T> iterator();
}

Last but not least I provided a static adaptor function to convert any Iterable<T> to a Queryable<T>:

static <T> Queryable<T> from(final Iterable<T> range) {
    return new QueryableImpl<T>() { 
        @Override
        public Iterator<T> iterator() {
            return range.iterator();
        }
    };
}

Putting all together allows you to write the following Java code:

Iterable<Float> src=
    Arrays.asList(0f, 1f, 2f, 3f, 4f, 5f, 6f, 7f, 8f);

UnaryFunction<Float, Integer> xform =
    new UnaryFunction<Float, Integer>() {
        public Integer execute(Float arg) {
            return (int) arg.floatValue();
        }
    };

UnaryFunction<Integer, Boolean> less5 =
    new UnaryFunction<Integer, Boolean>() {
        public Boolean execute(Integer arg) {
                return arg < 5;
        }
    };

Iterable<Integer> i2 = 
     from(src).select(xform).where(less5);

This looks pleasant close to the C# original!

No comments: