Hackers and Painters

Phred on 2005-01-19T05:21:33

My coworker Michael Peters lent me his copy of Hackers and Painters by Paul Graham yesterday. I'm sure many of you have read this excellent book, so I'm going to avoid giving a full blown review here and talk about a section of it where does a comparison of Ruby, Lisp, Perl, and a few other high level languages.

"We want to write a function that generates accumulators - a function that takes a number n, and returns a function that takes another number i and returns n incremented by i."

Here's how it's done in Lisp:

(defun foo (n)
  (lambda (i) (incf n i )))

And in Ruby:

def foo (n)
  lambda {|i| n += i } end

And Perl 5:

sub foo {
  my ($n) = @_;
  sub {$n += shift }
}

Let's not forget Smalltalk

foo: n
  |s|
  s := n
  ^[:i| s := s+i. ]

Javascript...

function foo(n) {
  return function (i) {
           return n += i } }

Python...

def __init__(self, n):
    self.n = n
def __call__(self, i):
    self.n += i
    return self.n

And Java:

public interface Inttoint {
  public int call(int i);
}

public static Inttoint foo(final int n) {
  return new Inttoint() {
    int s = n;
    public int call(int i) {
    s = s +i;
    return s;
    }};
}

Whew! That was a lot of typing. He comments that the programmer has to extract variables manually in perl. But one thing that jumps out at me about the perl function is that i does not have to be declared. In every other language i is used twice in the function.

Now I am biased, and I've used Perl substantially more than any of the other languages listed here. I think that the Ruby solution is probably the most elegant - two lines of code, with distinct operators such as |, but the input i to the function still must be declared, it isn't obvious to me that you can directly manipulate the data structure containing the input arguments (Disclaimer: I've never written a line of Ruby in my life).

That's what I love about Perl - you can get at the data anyway you desire and are not held back by syntax.