Tuesday, May 26, 2009

Scripting rocks! (Java vs Ruby)

So I was just in Borders looking at the programming books, and I remembered my frustration programming with Java again for Android. It seemed to needlessly verbose compared to scripting languages like Ruby. Handling XML seems like a big point of difference. For handling XML in android I was looking at using all kinds of libraries:

1) JAXB (requires schema in advance)
2) JDOM (couldn't get it to work on Android)
3) SAXB (default - others built on this?)

compared with ruby's crack library where I can do something like this:
xml = '<posts><post><title>Foobar</title></post><post><title>Another</title></post></posts>'
# => {"posts"=>{"post"=>[{"title"=>"Foobar"}, {"title"=>"Another"}]}}
Combining this with the Mash class I can access a hash generated from an XML document like an object, like so:
# => "Foobar"
Anyhow, so in Java I just ended up building the closest equivalent I could on top of SAXB which involved dumping the xml structure into a Node Class with a Vector of children as well as an LinkedHashMap index mapping the element strings to Vectors of those children of that element, and a LinkedHashMap of attributes, thus:

node.get("item") returns Vector of all children of type <item></item>
node.atts.get("att_name") returns attribute e.g. <att_name="frank"></item>

It all makes me wonder if there is a book on why scripting rocks somewhere, and I have also been having these ideas about how scripting works as being all about how simple it is to manipulate data structures. The key ones seem to be collections of objects and hashes. So much stuff seems to come down to manipulating one of those two in some way; and making the syntax for handling those two as magically simple as possible seems key. Even using the advanced for loop in Java, trying to dump information about an http request took a lot of effort.

HttpResponse response1 = client.execute(post); # gives http status code
Log.d("DEBUG", response1.getStatusLine().toString());
array = response1.getAllHeaders();
for (Header h: array) {
Log.d("DEBUG", h.toString()); # gives all the http response headers
long length = response1.getEntity().getContentLength();
byte[] response_bytes = new byte[(int) length];
response1.getEntity().getContent().read(response_bytes); # gives the http response body
Log.d("DEBUG", new String(response_bytes));

which in Ruby would have been something like
Net::HTTP.start('api.iknow.co.jp', 80).do |http|
res = http.request(req)
puts res.code # gives http status code
puts res.to_hash.inspect # gives all the http response headers
puts res.body # gives the http response body
Of course I also love Ruby mixins and the lack of multiple inheritance support in Java seems particularly disturbing. In this case I was particularly frustrated by wanting to print out the headers, and calling array.toString() gives me something like [Ljava.lang.String;@89ae9e. Now I can see the argument that this is sensible default behaviour and that it is then up to the programmer to implement alternative pretty print outs by overriding toString() in a sub class, but I am not sure that this is possible in Java. In Ruby I could simply insert the necessary functionality using a mixin or similar. There is some discussion on how to achieve this in Java in mailing lists, e.g. here, but all the solutions are awkward and complex.

I mean Java ends up being so much more verbose. Maybe it is much much more efficient, and this complexity supports all sorts of things that I'm not thinking about, but this is pretty much the point - most of the time I'm not thinking about them. Most of the time I want to explore something without having to worry about grabbing the length of the http response body, reassigning its type and then creating a byte array to store the results in. I just want to see the body. I'll come back later and optimise if I need to.

Perhaps I am missing some clever java scripting tricks, in which case please let me know, but I do find it quite painful dropping back to Java after scripting with Ruby.

1 comment:

Sam Joseph said...

Philip Johnson sent me this great review of the effectiveness of ruby in projects by the thoughtworks team: http://martinfowler.com/articles/rubyAtThoughtWorks.html