Metaphysical Developer

Literal Collections In Java

Posted in Languages by Daniel Ribeiro on May 23, 2009

Terse ways to express Literal Collections such as Maps and Lists can be useful when building an Internal DSL. Java is famous for not having any facility to craft those. It does have literal object arrays, but these are a bit awkward when nesting, which is usually what you are going to do when employing this technique. But using variable arguments functions can supplement this deficiency quite nicely.

Below I show some ways to achieve this using an useful import static from import static org.fluentjava.FluentUtils.*. I also comapare with the original ruby examples from Martin Fowler’s DSL Book.

  • Lists and Maps in Java
  • alist("computer",
      alist("processor", map(pair("cores", 2), pair("type", "i386"))),
      alist("disk", map(pair("size", 150))),
      alist("disk", map(
       pair("size", 78),
       pair("speed", 7200),
       pair("interface", "sata")))
  • Lists and Maps in Ruby
  • [:computer,
     [:processor, {:cores => 2, :type => :i386}],
     [:disk, {:size => 150}],
     [:disk, {:size => 75, :speed => 7200, :interface => :sata}]
  • Just Lists in Java
  • alist("computer",
      alist("processor", alist("cores", 2), alist("type", "i386")),
      alist("disk", alist("size", 150)),
      alist("disk", alist("size", 78), alist("speed", 7200),
        alist("interface", "sata")));
  • Lists and Pairs in Java
  • alist("computer",
     alist("processor", pair("cores", 2), pair("type", "i386")),
     alist("disk", pair("size", 150)),
      pair("size", 78), pair("speed", 7200), pair("interface", "sata"))
  • Just Lists In Ruby
  • [:computer,
      [:cores, 2,],
      [:type, :i386]],
      [:size, 150]],
      [:size, 75],
      [:speed, 7200],
      [:interface, :sata]]]
  • Using a symbol as a vararg function (Java only)
  • $("computer",
     $("processor", $("cores", 2), $("type", "i386")),
     $("disk", $("size", 150)),
     $("disk", $("size", 78), $("speed", 7200), $("interface", "sata"))
    private FluentList<Object> $(Object... args) {
       return alist(args);

From the comparison, it is easy to see that ruby is bit more appropriate for this technique (and so are other languages such as python, perl and lisp). However, some cleverly defined (or imported) functions can help Java code benefit from it as well.

Tagged with: , , , ,

Closures, Collections and some Functional Programming

Posted in Languages by Daniel Ribeiro on May 2, 2009

Collection libraries are quite common today in almost all languages, and we are very glad that every non trivial piece of software does not require us to define again what a List is, neither what a Tree is. Also, we do not have to keep on reimplementing basic algorithms such as sort. Some languages even provide literal ways to define the most commonly useful collections, such as lists and maps.

Closures (also known as blocks and lamba expressions) are also common on several languages (Java and C++ being notable exceptions), even though it only started becoming more mainstream with Ruby. Besides being useful on creating DSLs , they allow us to easily define callback procedures on GUIs, declare transactions, readily craft simple implementations of Visitors and Commands patterns, enable controlled lazy evaluation on languages that do not natively support it, refactor complex switch statements to a simple map leading to Closures, and so on.

Even though closures and collections are useful on their own, when combined they allow us to abstract iteration mechanisms. Smalltalk is notable for blending closures and collections in a category of methods that form a protocol called enumeration protocol. For instance (examples in ruby, that also features an enumeration protocol, similar to smalltalk), we can rewrite this:

novels = []
for b in books
  if b.novel?
    novels << b

Into this: {|b| b.novel?}

This way the code gets clearer, more concise and more simple, while encapsulating the actual iteration algorithm, which allow us to reuse the very same filter whether the books are coming from a list, from a file, from a database, or from a SOAP request. Not only that, but it allows us to refactor several filters of books into one line methods:

class Books
  def novels()
    return {|b| b.novel?}

  def older_than(year)
    return {|b| b.age > year}

  def name_starts_with(str)
    return {|b|[0, 1] == str}

But abstract iteration mechanisms are more than just filtering. Common enumeration protocols (such as those from Ruby and Smalltalk) features several methods to detect elements, to create new maps with a function, sort elements, get the maximum and minimum elements (using a closure as a definition of comparison) and so on. Many of these are inpsired by functions orginally defined on functional programming languages, such as fold and map.

The encapsulation of iteration mechanism is also usefull when we want to start using coarse-grained parallelism, such as proposed by Fork Join (which, ironically is written in a language that does not have closures) . That is: you had a sequential code, and with very little alteration, you can get a parallel/distributed one (while being cautious of side effects). In our example: Books#novels could be very well selecting the novels in separate threads, and joining them all together. It would only be a matter of changing the implementation of @books.

Concluding: Closures and Collections allows us to improve code by:

  • making it more concise
  • making it clearer
  • making it more suitable to refactoring
  • making sure you Don’t Repeat Youself
  • enabling you to easily turn sequential code into parallel

Considering that all of these points are too good to let go, and considering that java 7 will not get closures and that not only are anonymous inner classes really closures but also too verbose, I started a little project called Fluent Java. This project, among other things, brings up the enumeration protocol to java, while still keeping it terse, and easy to use (Fork Join integration is planned as well).

Edit: Java might get simplified closures after all (at least, for now, it is planned). But still too early to say regarding how this was already pulled off once, and Oracle has some issues to work through with Sun, which may push JDK7 to being released early.

Edit (22 Sep 2010): Yes, it got pulled away. From the Chief Architect of the Java Platform Group: It’s time for … Plan B. Scala has them though…