Title: Practical OCaml
Author: Joshua B. Smith
Technical Reviewer: Richard Jones, of Merjis
Publisher: Apress, part of the Practical series (which published, notably, Practical Common Lisp)
The concept behind the book is brilliant: shed some light on how OCaml can be used for practical coding. All the ivory tower academics are constantly touting the merits of type-safety and functional programming, but hardly anyone actually uses functional programming for real, practical work. There are only a small handful of significant open-source programs written in OCaml, and even now very few companies have embraced the language.
It's a great idea to show how OCaml can be used to write real world applications. It's clear from the title, overview, and structure of the book that Joshua Smith wants to emphasize OCaml's practicality: his sample code includes "A URI Library," "A Spam Filter," and "A Shoutcast Server." For this essential insight, I applaud Mr. Smith.
Unfortunately, that's about where the praise has to stop. This book has several serious flaws, that render it virtually useless. In fact, this book's existence will probably cause significant harm to OCaml's reputation.
Let's start with the writing. In the "About the Author" section, we learned that the author was, in fact, an English major in college. So we expect some good english--hopefully better than most dry technical books written by dry technical folks who know lambda calculus but don't know what an adverb is.
Let's take a few examples:
In fewer than 100 lines of code, you can see the code that provides much of what you see on the screen. This is a simple, file-based web log such as CGI. It creates the disk files named by using an MD5 hash of the data within the file, which makes the likelihood of collision so small as to be a nonissue. If I were more concerned, I would add the time to the string used to calculate the MD5 hash, but I haven't done that.
Try reading the first sentence out loud. Doesn't make any sense, does it? The second one is no better, if you know what CGI is (it's definitely not a type of "file-based web log"). The remaining discussion about the MD5 hash is almost readable, but it has technical problems (1: using an MD5 hash for the filename is a terrible idea; 2: adding the time isn't going to make any significant improvement to this terrible idea).
Okay, so he had a bad paragraph. Lighten up? I would love to, but the whole book is like this. Let's try the intro to the next section:
But I Want to Add Cookies!
Here is where the drawbacks of rolling your own become apparent. You have your blog application running, but now you want to add authentication. To add support for it, you have to add it myself.
Admittedly, the use of "myself" instead of "yourself" is a simple grammatical error. But rest assured, the book is riddled with similar errors. I did not look hard for these. And the guy is an english major, so this sort of thing is supposed to be his strong point.
The first page has an overview where he tries to answer the question: Why Objective Caml? He answers with an analogy:
To answer in not-so-mundane terms, we can compare what an architect might want in building materials versus what a carpenter might want in building materials. An architect wants the best materials to build with, but a carpenter wants the best materials to work with. This is as it should be--the carpenter values the work and wants to do it well. The architect, however, might not have the specific concerns the carpenter does. This is as true in software as it is in wood.
Huh? Who is better, the architect or the carpenter? What does this have to do with programming? Ah, he goes on in the next paragraph, surely he'll explain it:
As a programmer, I want good materials. OCaml is one of the best materials I can think of.
..need I say more?
But I'm going to. A technical book like this need not be well written to be useful. After all, it's teaching you how to code, so it's got tons of code examples. Examples, when thoughtful, concise, and correct, can be very helpful. Bummer that the examples in Practical OCaml have none of these properties.
The first and most obvious problem is the formatting of the code. It's a bit hard to explain, but the code samples have these little arrows all over that mean "this line continues" because the code didn't all fit on one line. Usually this is because there's too much code trying to squeeze into one line. An example
(***marks the spot where the little arrow is in the actual text):
let print_position pos = print_string "Holding: ";print_int ***
pos.holding;print_string (" " ^ pos.symbol ^ "@");
print_float pos.pprice;print_newline ();;
Nobody indents their code like this. It's completely unreadable. The same function, properly indented, should look like:
let print_position pos =
print_string "Holding: ";
print_string (" " ^ pos.symbol ^ "@");
Actually, since we learned about the printf function earlier this chapter, let's see how much more concisely and cleanly we can write this code:
let print_position pos =
printf "Holding: %d %s@ %f\n" pos.holding pos.symbol pos.pprice
Enough about indentation. What about content?
module type LIFER =
val xdim: int;
val ydim: int
val results: int * int * int * int * int * int * int * int -> int -> int
val default_colormap: int -> char * char * char
val default_mapcolor: char -> char -> char -> int
What in the world is a
results? A function that takes an 8-tuple of ints, then one more int, and returns an int? What are all these ints? Any OCaml programmer would look at this and say it's very bad style, because it's extremely hard to read. It should be a record instead. Let's go on..
match res with
remain when (res = 2) -> x
| live when (res = 3) -> 1
| gain when (res = 4) -> 2
| more when (res = 5) -> 3
This is not only confusing, it wouldn't even compile. Well, depending on your compiler settings, it might compile, but the compiler would complain loudly because
moreare not even used. Here is code that is simpler, doesn't create a compiler warning, and does the exact same thing as the above code:
match res with
| 2 -> x
| 3 -> 1
| 4 -> 2
| 5 -> 3
Heck, we could even write it like this:
... if res = 2 then x else res - 2 ...
And this is just basic pattern matching; elementary OCaml stuff.
These are some of the more glaring and easily visible issues that I've happened across during a recent perusal of the book. There are other, much more insidious types of problems which require a reasonable understanding of OCaml to catch. For example, the first demonstration in the object chapter shows how to use the object system to automate the initialization of the random number generator:
class random =
method int x = Random.int x
method float x = Random.float x
method rand () = Random.float 1.
initializer Random.self_init ();Printf.printf "Random Constructor"
What he's clearly missing here is that when you call
Random.self_init (), this re-initializes the random number generator in a global, stateful way. So the whole notion of encapsulating the initialization of the random number generator is lost. In fact, the entire two-page example is based on a false premise.
Anyone who wants to learn OCaml should stay away from this book. It will only confuse. This is unfortunate, as the idea to shed light on the practicality of OCaml is an excellent one. I'm rather shocked that Richard Jones signed on to be technical editor, and that he let the book be published in this state (edit: see his explanation in comment #2 below).
I would urge any and everyone to not buy this book, and don't let your friends read it; it will taint their view of OCaml and quite possibly confuse them enough to keep them away from OCaml forever.