Some C# Features for Java

by Michael

Programming in different languages is both great and frustrating. Frustrating because you want to be able to use feature X of a language in another language, but the language you’re using doesn’t support that feature. This is very true for anyone that has used a somewhat more functional or dynamic language and then started (or went back to) programming in a language like Java. One of the key philosophies of the Java language is to keep things simple. I appreciate this philosophy, and in fact feel that perhaps adhering to OO-programming has made things more complex than what they need to be. This is one of the reasons I started playing around with Clojure – a simple and flexible language that allows you to be very productive. But, It’s not easy to switch and start thinking in terms of verbs instead of nouns.

I digress.

Most of the features that I look for are implemented in C# and since it bares close resemblance to Java, I attempted to implement some of those features:

  • coalesce operator ??
  • TryParse methods
  • IsNullOrEmpty test for strings
  • Loan pattern implementation with using
  • a subset of LINQ for objects

TryParse isn’t really what I had hoped since one cannot use references for numbers, not even when they are boxed. All these methods are implemented as static methods:

coalesce(null, objectThatIsNull, someObject)
>> someObject

tryParseInt("10")
>> 10

tryParseInt("g")
>> null

isNullOrEmpty(null)
isNullOrEmpty("")
>> true 

// closes the OutputStream automatically, calls
// close on any class that implements Closeable
tryWith(new OutputStream(), /* some function here */)

LINQ-ish

I focused on a subset of the LINQ implementation, only implementing operations that seemed fundamental, plus some more that were easy to write. The underlying code uses Iterable interface, we don’t hold any collections and values are only generated when we traverse the items.

Generators

Methods that produce an iterable such as range(start, end, step) as well as repeat(item, repetitions).

List expecteds = new ArrayList();
expecteds.add(5);
expecteds.add(9);
expecteds.add(13);
expecteds.add(17);
expecteds.add(21);
expecteds.add(25);
expecteds.add(29);

Iterators.rangeInt(5, 30, 4)
    .zip(expecteds)
    .each(new Proc1<Tuple2>() {
        @Override
        public void apply(Tuple2 arg) {
            Assert.assertEquals(arg.getItem1(), arg.getItem2());
        }
    });

all and any

Do any or all items in the list satisfy a certain predicate.

Collection strings = new LinkedList();
strings.add("a");
strings.add("a");
strings.add("a");

boolean expected = true;

boolean actual = from(strings).all(new Func1() {
    @Override
    public Boolean apply(String arg) {
        return arg.equals("a");
    }
});

Assert.assertEquals(expected, actual);

map, reduce and filter

These operations give you the basic toolkit for data manipulation. Note that you can pass up to four functions into map to produce a list of tuples. Filter, in theory, can be implemented using the reduce operation but I chose to make it independent of reduce.

List strings = new LinkedList();
strings.add("a");
strings.add("a");
strings.add("b");
strings.add("a");
strings.add("a");

int total = from(strings)
		.map(new Func1() {
			@Override
			public Integer apply(String arg) {
				return arg.hashCode();
			}
		},
		new Func1() {
			@Override
			public String apply(String arg) {
				return arg.toUpperCase();
			}
		})
		.filter(new Func1<Tuple2, Boolean>() {
			@Override
			public Boolean apply(Tuple2 arg) {
				return arg.getItem1 == 97;
			}
		})
		.reduce(0, Functions.sumInt());

take and drop

Take (use) the first x items, drop (ignore) the first x items.

final Integer expected[] = {30, 31, 32};

Iterators.rangeInt(30, 100).take(3).each(new Proc1() {
    int count = 0;
    @Override
    public void apply(Integer arg) {
        Assert.assertEquals(expected[count++], arg);
    }
});

wrap

This one is a bit special and is inspired something I found in Clojure. It wraps an already existing list so that the list repeats itself to infinity – 1, 2, 3 becomes 1, 2, 3, 1, 2, 3, 1, 2, 3, …

String expected = "a/b/c/a/b/c/a/b/c/a";
String actual = from("a", "b", "c")
                    .wrap()
                    .take(10)
                    .reduce("", Functions.join("/"));

Assert.assertEquals(expected, actual);

I’ve implemented more methods that I didn’t discuss here such as sort and zip. The source code can be found here on GitHub. All this would be so much nicer with lambda expressions 😥

Advertisements