10 Things I've Learned from other Languages

From EggeWiki

One of the sessions at JAOO Sydney 2008 was on Multi-language programming. I've long been an advocate of learning multiple programming languages, especially after I read the book Hackers & Painters by Paul Graham.

Having learned a number of different languages over the years, I've found various techniques which can be applied broadly. Here are some of the things I've taken away from different languages:

1. Python Lamda calculus

<geshi lang="python"> print map(lambda w: len(w), 'It is raining cats and dogs'.split()) [2, 2, 7, 4, 3, 4] </geshi>

Traditional Java: <geshi lang="java"> String[] split = "It is raining cats and dogs".split(" "); int[] lengths = new int[split.length]; for(int i = 0; i < split.length; i++) { lengths[i] = split[i].length(); } System.out.println(Arrays.toString(lengths)); </geshi>

Python like Java: <geshi lang="java"> private interface Function<I,O> { O calculate(I input); } private static class len implements Function<String, Integer> { public Integer calculate(String s) { return s.length(); } } public static <I,O> List<O> map(Function<I,O> function, List list) { List<O> output = new ArrayList<O>(); for (I i : list) { output.add(function.calculate(i)); } return output; } System.out.println(map(new len(), Arrays.asList("It is raining cats and dogs".split(" ")))); </geshi>

Although the second version contains a lot more code, the various parts are reusable. While Java will never be able to support higher order functions, you can make use of functors. Another reason to use functors is the ability to plug them into a concurrency framework like fork-join. In the first example, where you wrote the loop yourself, you can't easily make the function utilise multiple cores. With something like fork-join, you can run your function unmodified buy passing it to a concurrent executor.

2. Ruby Closures

Closures are another functional concept which allows functions to be method arguments. There are multiple proposals to add closures to the Java languages. In Java, closures can mostly be faked by using anonymous inner classes. For example, here's the Ruby way to print the contents of a file.

<geshi lang="ruby"> File.open("Languages.java", "r") do |infile|

   while (line = infile.gets)
       puts "#{counter}: #{line}"
       counter = counter + 1
   end

end </geshi>

Traditional Java <geshi lang="java"> File file = new File("Languages.java"); FileInputStream fis = null; InputStreamReader isr = null; BufferedReader br = null; try { fis = new FileInputStream(file); isr = new InputStreamReader(fis); br = new BufferedReader(isr);

int counter = 0; String line; while ((line = br.readLine()) != null) { System.out.println(counter + ": " + line); counter++; } } finally { if (br != null) br.close(); if (isr != null) isr.close(); if (fis != null) fis.close(); } </geshi>

The Ruby way of doing the same in Java would be:


<geshi lang="java"> public interface LineReader { void each(String line); } private static class ReadFile { private final File file;

public ReadFile(String f) { this.file = new File(f); }

public void each(LineReader f) throws IOException { FileInputStream fis = null; InputStreamReader isr = null; BufferedReader br = null; try { fis = new FileInputStream(file); isr = new InputStreamReader(fis); br = new BufferedReader(isr);

String line; while ((line = br.readLine()) != null) { f.each(line); } } finally { if (br != null) br.close(); if (isr != null) isr.close(); if (fis != null) fis.close(); } } } private static void ruby() throws IOException { new ReadFile("Languages.java").each(new LineReader(){ int counter = 0; public void each(String line) { System.out.println(counter + ": " + line); counter++; }

}); } </geshi>

Again, there's a lot of boiler plate, however, now, I don't have to write the same resource acquisition and release code next time I want to read a file. This is done by Spring JDBC, and helps encourage separation of concerns.

3. Perl CGI programming

Perl makes it drop dead easy to create an interactive web page. You can get a Perl CGI page working faster than reading the first page of the Java servlet spec. Learning web programming at the HTTP level isn't as difficult as framework authors might make it out to be, and a firm understanding of the protocol can help understand exactly what a framework is doing to help you out. Your first CGI page might look like this:

<geshi lang="perl">

  1. !/usr/bin/perl -w
    print "Content-type: text/html\n\n";
    print "Hello, world";

</geshi>

4. J sparse arrays

5. APL Your workspace is your environment

6. Tcl All operations are commands