Why O’Caml is not my favorite programming language

A few hours ago the ICFP Programming Contest 2007 ended, and the team Funktion im Kopf der Mensch participated again, this year slightly demotivated by the fact that the organizer’s main goal seems to have been to show off how smart they are instead of letting the participant practice their creative skills.

As always we were using Objective Caml for most of our programming work. O’Caml has always had some annoying sides, but this year I ran into so many of them that I got seriously pissed off, and will now have to investigate other options.

For us, O’Caml’s main attraction are its type system, which, when used correctly, makes it surprisingly hard to write incorrect code, and its performance. O’Caml’s big weakness is its standard library. To be frank, it sucks, big time.

I’ll present the issues I ran into during the past three days, and I’ll compare the way O’Caml handles those things with Common Lisp, because in the areas I’ll discuss here, it is a good example of how to do it right. Note that I’m not saying that Common Lisp does everything else better. There is a reason why we’ve been using O’Caml, after all.

Let’s start with numbers. Say we need a function which adds the number 3 to a given number. Should be a trivial task, right? Indeed, in Lisp it is:

(defun add-3 (x)
  (+ x 3))

Let’s see if it works:

[2]> (add-3 0)
3
[3]> (add-3 4.5)
7.5
[4]> (add-3 3/2)
9/2
[6]> (add-3 (sqrt -4))
#C(3 2)

Great – we can give the function any kind of number, and it adds 3. How do we implement this in O’Caml? Well, first we’ll have to decide which kind of number we want to operate on, because, you see, you can’t mix different kinds of numbers. Ok, let’s concentrate on integers. There can’t be more than one kind of them, can there? Well, it turns out there are several. There’s “int”, “int32”, “int64”, “nativeint” and “big_int”. Here’s the code for all of them:

let add_3_int x =
  x + 3
let add_3_int32 x =
  Int32.add x (Int32.of_int 3)
let add_3_int64 x =
  Int64.add x (Int64.of_int 3)
let add_3_nativeint x =
  Nativeint.add x (Nativeint.of_int 3)
let add_3_big_int x =
  add_big_int x (big_int_of_int 3)

And those are just for the integer types! How ridiculous can it get?

Next issue: Arrays. Let’s say we need a function which returns an array with all the elements of the array it was given in reverse order, except for the last one. A triviality in Lisp:

(defun chop-rev (seq)
  (reverse (subseq seq 0 (1- (length seq)))))

Let’s see if it works:

[10]> (chop-rev #("abc" "123" "xyz"))
#("123" "abc")
[9]> (chop-rev "abcdef")
"edcba"

Notice that in Lisp string are arrays, too. As an added bonus, our function even works on lists:

[8]> (chop-rev '(1 2 3 4))
(3 2 1)

What can O’Caml do for us? Again, we first need to ask: Which kind of arrays are we talking about? There’s the built-in array type “array”. Then there’s strings, which O’Caml doesn’t treat as arrays, for no apparent reason. There’s another type called “Buffer”, which is really just a string that can grow, but is, of course, completely incompatible with “real” strings. There’s also something called “bigarray”, which is an array that can be big. In any other language such a data structure would be obsolete, because standard arrays wouldn’t have any size limits. Not so in O’Caml! You can enjoy all the comforts of the built in array type, but only if you don’t need to put in more than about 4 million elements (on 32 bit systems), unless you work with floats, in which case you’re limited to 2 million elements. Perhaps I should also mention that strings are limited to 16 million characters, but they forgot to implement big strings. What a joy!

Hack Week Conclusion

My work for hack week has ended, and I’m pretty satisfied with it. Since the last update I’ve integrated my C imaging code into the application, removed the dependency on GEGL and improved the UI a bit. The application is now in a state where it is already somewhat usable. The big thing that’s missing is dodging and burning. Apart from that there are several small things that still need to be done, like the histogram. Oh, and the UI needs to be seriously improved, because it sucks. As soon as I have time again I’ll continue working on the project.

For anybody who wants to give it a try or maybe even put some work in, the application can be downloaded in two parts: First there’s the image processing library, which is written in C and should be trivial to compile. Then there’s the application itself, which can be built with MonoDevelop. A few hints about using the program: “Import” brings in an image for processing. “Export” saves the processed image in the PNG format. Clicking on the image “inspects” the pixel clicked on, and shift-dragging the image scrolls.