Wednesday, June 25, 2008

The Blub paradox

Yesterday I read someting interesting concerning how programming languages are compared:

«[T]o explain this point I'm going to use a hypothetical language called Blub. Blub falls right in the middle of the abtractness continuum. It is not the most powerful language, but it is more powerful than Cobol or machine language.

And in fact, our hypothetical Blub programmer wouldn't use either of them. Of course he wouldn't program in machine language. That's what compilers are for. And as for Cobol, he doesn't know how anyone can get anything done with it. It doesn't even have x (Blub feature of your choice).

As long as our hypothetical Blub programmer is looking down the power continuum, he knows he's looking down. Languages less powerful than Blub are obviously less powerful, because they're missing some feature he's used to. But when our hypothetical Blub programmer looks in the other direction, up the power continuum, he doesn't realize he's looking up. What he sees are merely weird languages. He probably considers them about equivalent in power to Blub, but with all this other hairy stuff thrown in as well. Blub is good enough for him, because he thinks in Blub.

When we switch to the point of view of a programmer using any of the languages higher up the power continuum, however, we find that he in turn looks down upon Blub. How can you get anything done in Blub? It doesn't even have y.

By induction, the only programmers in a position to see all the differences in power between the various languages are those who understand the most powerful one. (This is probably what Eric Raymond meant about Lisp making you a better programmer.) You can't trust the opinions of the others, because of the Blub paradox: they're satisfied with whatever language they happen to use, because it dictates the way they think about programs.»


Check this out to read more about how to evaluate programming languages.

Wednesday, June 4, 2008

LISP's mapcar for Java: onAll-collect

I've been working on a project were I need to iterate over a set of objects, get some property from all objects in the collection, and store that property in a new collection. This wouldn't be much if an issue if I did it in LISP or Ruby or some think similar... but this is done in Java with th the java.util.Collection framework. The Collection framework is nice and all, but when I have to write:


List<SomeProperty> allProperties(List<SomeClass> objects) {
  List<SomeProperty> properties = new ArrayList<SomeProperty>();
  for (SomeClass c : objects)
    properties.add(c.getProperty());
  return properties;
}

when all I really wish to say is:

(defun all-propreties (objects)
  (mapcar get-property objects))

I get a bit sad. Sure computer technology is progressing, but are computer languages? LISP appeared in the late 50-ies and Java in the mid 90-ties, but looking at the code above I can't really tell that there is almost 40 years between these two languages. Crazy...

Anyway, to make me a bit happier I started to think about how the Java code above could be improved to make it a little bit more terse. What I came up with was this:


List<SomeProperty> allProperties(Bag<SomeClass> objects) {
  return objects.collect(objects.onAll().getProperty());
}

which I honestly think is pretty neat. Then again, I'm just an ape-descended life form who are so amazingly primitive that I still think digital watches are a pretty neat idea too.

How does this work? Well, first of all the objects variable is not the same type in the two Java examples above. In the latter example, it is a class that I've implemented specially to deal with the scenario described. This class, which is called Bag<T>, has a method onAll(T) that returns an dynamic proxy implementing the T interface. That is, in the example above the objects.onAll() returns an instance of the SomeProperty interface.

This dynamic proxy handles every method call it receives by calling that method on each object in the Bag. Also, if the called method is non-void, then it returns whatever the last object in the Bag returned. This means that bag.onAll().someMethod() behaves just as thing.someMethod() if bag contains just the thing objects. This is a Good Thing in my book. :)

How about the Bag.collect method?, you ask. Funny you should ask that. I was just getting to that, I reply. Cut to the chase already!, you say. Cool it, I say, or there won't be any desert!.

(Ok, I'm getting a bit carried away.)

The Bag.collect simply returns the set of return values got when last calling a method on the onAll-object. Ehm, it a bit hard explain with words... but I think you understand. If you don't, look at the code and test-cases. :)



Note that the onAll method returns an object that can be used for more than what's described above. Whenever you need to treat a set of objects as if they were one object, for instance the Observer pattern, the onAll-object simplifies alot.