The Poor Man's Lambda
I've been putting some more work into my little Linq for Java demo lately to make the tests for all the examples in the Linq samples demo pass. Some of these are going to be pretty challenging, but I'm well on my way. In general I believe the DSL is highly readable, but the lambda expressions are by far as elegant has those of C# 3.0. Consider the following demo from the samples in the Orcas CTP.
public void Linq5() {
string[] digits = { "zero",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine" };
var shortDigits = digits.Where((digit, index) => digit.Length < index);
Console.WriteLine("Short digits:");
foreach (var d in shortDigits) {
Console.WriteLine("The word {0} is shorter than its value.", d);
}
}
It's Java counterpart currently looks like this:
@Test
public void canUseRestrictionPredicate()
{
String[] digits = {"zero",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine"};
Object[] shortDigits = (Object[])
from(digits).where(new Predicate()
{
public boolean eval(Object elm)
{
return
((String)elm).length()<getContext().getIndex();
}
}).select();
String[] expectedDigits = {"five",
"six",
"seven",
"eight",
"nine"};
for (int i = 0; i < expectedDigits.length; i++)
{
Assert.assertEquals(expectedDigits[i],shortDigits[i]);
}
}
The key difference between the two is the predicate used to restrict the selection. In the C# example this is a compact lambda expression, while in the Java version it is an anonymous inner class which implements a template method. The inner class provides access to a criteria context instance which provides things such as the element's index are made available.
If I had targeted the Java 7 runtime, I could have gotten a way with a tidier predicate using the proposed closure syntax.
from(digits).where(boolean(String elm)
{ return elm.length() < getContext().getLength(); }
).select();
I can improve the DSL by using generics to a greater extent, but still there is a long way to go before it has the full elegance of Linq. On the upside, most developers will probably find the template method approach easier to read the the "cryptic" lambda expressions of C#. To quote an anonymous reader on Sun's Java forum:
"Functions without a name?
No, functions belong to classes, and every class method has a name.
You want to use lisp!"