In the previous article, I wrote the "graph to csv" converting code in Python, because I thought it would be a suitable tool for the job. A few years ago, I ran a workshop with Keith Braithwaite called "Why Java programmers should learn Python", one of the premisses being that you should choose the correct tool for the job; Java isn't the best language for every problem. Too many Java programmers, particularly many graduates these days whose degree courses are dominated by Java, don't have a wide enough experience of other styles of language. Learning other languages is both good for your brain and often useful.
There are some problems for which using Python can get you a solution sooner than Java, and the "type safety" of Java and other statically typed languages is often less important than you might think. Today, I thought I'd see what the Python code from the previous article looked like if re-written in Java to see if it would shed any light on these assertions.
Here is a Java version of the code - I've tried to make it reasonable - if you can see any improvements for either version, then please feel free to post them as comments, or post on your own blog and put a link in a comment.
package com.oocode;
import java.io.*;
import java.util.*;
public class Graph2Csv {
public static void main (String[] args) throws IOException{
Map<String, Integer> incoming = new HashMap<String, Integer>();
Map<String, Integer> outgoing = new HashMap<String, Integer>();
Set<String> nodes = new HashSet<String>();
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
String line = input.readLine();
while(line != null){
if(line.contains(" -> ")){
String[] parts = line.split(" -> ");
String source = parts[0];
String destination = parts[1].substring(0,parts[1].length()-1);
increment(incoming, destination);
increment(outgoing, source);
nodes.add(source);
nodes.add(destination);
}
line = input.readLine();
}
System.out.println("incoming,node name,outgoing");
for(String node : nodes){
System.out.println(num(incoming,node)+","+node+","+num(outgoing,node));
}
}
private static int num(Map<String, Integer> incoming, String node) {
return incoming.containsKey(node) ? incoming.get(node) : 0;
}
private static void increment(Map<String, Integer> map, String node) {
if(!map.containsKey(node)){
map.put(node, 0);
}
map.put(node, map.get(node) + 1);
}
}
The Java version is slightly longer and I don't think the static typing adds either to the clarity or the correctness of the code. On the other hand there are some great Java IDEs that do most of the typing for you, so overall I probably made the same number of keystrokes in both cases. In this code, I think the new features of Java 5 made it better than if I'd used an older Java.
The type safety, or otherwise, doesn't affect my confidence in either version of the code nearly as much as the fact that neither version has automated tests. I've tested both versions manually with one sample input, and they both look like they work, but if either has a bug, it's not going to be spotted by static type checking, but by testing.
So why didn't I use TDD? Several reasons:
I'm writing it by myself, for myself, rather than as part of a team.
It's a small, standalone, throw away piece of code, not part of a larger project or code that other people are relying on.
I don't care much whether it works for anything other than the one input I wrote it for.
It didn't seem like the sort of code where I'd be quicker doing it TDD.
If you think your favourite language would be just the thing for this problem, then please post a comment containing the code, or a link to the code on your blog.
Posted by ivan at February 12, 2006 1:53 PMI think wondering about the static typing adding to the correctness of the code is a bit of a red herring: if the code is correct, it won't be more correct for being statically typed. Static typing just increases the probability that incorrect code will be detected early.
Posted by: Charles Martin at February 12, 2006 5:55 PMI sort of agree, but only a bit. There are indeed some errors that are detected by static typing earlier than when using dynamically typed languages.
However, there are many more ways in which even pretty simple code, like that shown here, can be incorrect that are not detected by type checking alone. The presence of static type checking should not be an excuse for an absence of testing.
If you have to test code anyway (whether it's statically typed or not, which I think you most definitely do have to) then I think any argument about the benefits of static typing should be on the basis of productivity or maintenance rather than correctness of code, as static type checking makes no difference to the correctness of tested code.
Posted by: ivan at February 12, 2006 6:40 PMI think it's unfair to use Java (even Java 5) in a dynamic versus static typing debate. Java's static type system is archaic with insane generics and insane autoboxing cobbled together on top. Why not compare dynamic typing with a modern type system (Haskell, for example). Dynamic typing would still win time-wise, but the Haskell code would be much cleaner than the Java above.
Posted by: Nat at February 13, 2006 10:04 AMHi Nat,
I'd be interested to see how this looks in Haskell (and OCaml). I think it's a more realistic language comparison than Paul Graham's example problem http://www.paulgraham.com/accgen.html, without being too big.
Ivan
Posted by: ivan at February 13, 2006 2:14 PM