Ken Williams [email protected] is a Research Scientist at Thomson Legal and Regulatory in St. Paul, MN. He is the primary author of several CPAN modules, including Module::Build, Path::Class, Apache::Filter, and AI::Categorizer.
Five years is a long time to spend writing a computer book. If we are to believe the tired old adage that computing technology advances at the rate of doubling every 18 months, then about 90 percent of our present technical world wasn't around five years ago. In other words, when Mark Jason Dominus started writing Higher Order Perl, perhaps only 10 percent of his subject matter actually existed yet. Maybe this means we shouldn't believe the adage, or more likely, that it just doesn't apply very well to the writing of a book on Perl programming, but stillfive years is a long time to spend writing a computer book.
If you want to tilt the odds a bit better in your favor, you can choose a topic that's already been kicking around a while and isn't likely to change much over five years. A topic like the basic principles of Lisp programming.
This, oddly enough, is what Dominus has done: written a book on how the basic principles of Lisp programming can be applied in Perl programming. And the result isn't just good, it's absolutely excellent. His book reminds the reader, or at least this reader, that no matter how foreign and weird we may think the other camp is (and rest assured, they probably think the same of us), we can learn an awful lot by practicing thinking the way they do.
Functional Programming
Dominus's aim in Higher Order Perl is to show Perl programmers some of the techniques that are commonplace in Functional Programming. Functional Programming, exemplified in languages like Lisp, ML, and Haskell, is essentially a different philosophy of programming than we see in Imperative Programming languages like C or Pascal. In Imperative Programming, you think of a program as a sequence of commands; you tell the computer, "do this, then do this, then do this." The computer then performs the actions specified, and typically shows you the side effects (e.g., the output of print statements) of doing so.
By contrast, in pure Functional Programming, a program consists entirely of functions; you tell the computer, "here's how you do this, and here's how you do this, and here's how you do this other thing." Each function is built from other functions, and may even take functions as arguments and/or produce functions as output. The computer then evaluates some function that's been designated as the main function, and shows you its return value.
It's most useful to think of Functional vs. Imperative programming as a distinction in philosophies rather than as a strict categorization of programming languages. Just as any individual person may embody more than one philosophy of life, any individual language may enable more than one philosophy of programming. In fact, Lisp itself is not even considered a pure functional language, even though it certainly encourages its practitioners to use many Functional Programming techniques.
We as Perl programmers know that Perl is a postmodern mish-mash of many different languages that have, at one time or another, caught the fancy of Larry Wall and the rest of the Perl Porters. Clearly some pieces of the language, such as for loops, variable scoping, and assignment syntax, come more or less directly from languages like C. Our beloved regular expressions come from (and render pretty much obsolete) awk and sed. Our object-oriented mechanisms ultimately come from Smalltalk. The Lisp-ish elements, like dynamic typing of variables, runtime manufacturing of functions, and variations on Perl's map concept, are the chief concerns of Higher Order Perl.
Strengths and Weaknesses
The strengths of Higher Order Perl far outweigh the weaknesses:
- Dominus's writing style is extremely clear and conversational. Despite its length, this is the kind of book you'd probably want to read straight through, rather than just sticking on the shelf to use as a reference. Judging by statements he's made in interviews since writing the book, this seems to have been because he was trying very hard to avoid a stuffy academic tone that might turn off many readers (and would certainly be a lot less fun to read).
- The reader isn't treated like a baby. Although he never explicitly says so (which for some reason I found kind of refreshing), Dominus assumes that the reader is already conversant with Perl's syntax and common idioms, and is capable of looking up unfamiliar constructs without him having to tell you so. This lets him avoid writing many unnecessary hand-holding distractions in the text, and lets him concentrate on the difficult expository challenges he's laid out for himself.
- The examples never seem contrived or silly. Dominus has clearly given much thought to his examples, in part because they play such a central role in his exposition. Examples from Chapters 1, 2, and 3 often show up again in Chapters 4, 5, and 6 in demonstrations of how recently-demonstrated techniques can improve on previous material.
- For the vast majority of the book's audience (Perl programmers), the subject matter in the book will be refreshing and new. It's not yet-another-book on how to do such-and-such task in the domain of so-and-so; rather, it's a book on how to do nearly any task you encounter differently, and probably better.
- The discussion in Chapter 5 about how to convert recursive functions to nonrecursive functions was very nice, both because the technique is useful for its own sake and because it showcases Dominus's famous step-by-step style of transforming code into better code. He's been refactoring code publicly in his "Program Repair Shop" for longer than most of us have known the term "refactoring."
That said, Higher Order Perl isn't without weaknesses:
- Object-Oriented Programming, which is probably the biggest mindshare-stealer from Functional Programming, is given pretty short shrift. There's a one-page comparison of OOP and FP stuck in Chapter 1 that felt a bit unconvincing to me, but otherwise OOP isn't really discussed much in the book again. Personally, if I apply the techniques in this book, I'll probably do it in the context of an Object-Oriented paradigm, as I think many programmers would. It would have been nice to see some in-depth demonstrations of how the two paradigms can coexist nicely rather than compete for philosophical dominance.
- Chapter 8, "Parsing," shows us a lot of neat parsing tricks, but left me somewhat unconvinced that I'd actually use this approach to accomplish a real task. When I'm writing a real-world parser, I need the rule syntax to be as absolutely straightforward and declarative as possible, and the parser declarations in Chapter 8 end up looking sort of byzantine. On the other hand, the techniques allow for a degree of reuse that standard parsers often don't allow, somewhat akin to the way Perl's qr// operator allows us to build large regexes from smaller regex pieces. It would be good to see this capability either woven into existing parsing engines like Parse::RecDescent or given an interface that makes the parser definitions look prettier.
- The mathematician in me bristled a bit during the discussion in Chapter 6; here, Dominus is using infinite streams (produced by the creative combination of linked lists and closures) to represent mathematical structures like the iterative values of functions or coefficients of power series. Some details that get glossed over can end up being pretty importantfor example, the Newton-Raphson method is certainly very useful, but it can be very sensitive to the choices of initial guesses, a point of which I'm sure Dominus is aware, but that he seemed to turn a blind eye to. Anyone using this approach in a real application will have to deal with this; for instance, if they try to find the solutions of cos(x)=0 and use zero as their initial guess. Also, the discussion of various Calculus topics could have benefitted from a clear explanation that numerical methods were being used rather than analytical, lest some poor high school Calculus student get confused trying to align the discussion with what they're doing every day in their homework.
- The formatting relationship between the main text and the code examples was sometimes a bit jarring. From one page to the next, the inline code examples would sometimes be lined up to the left of the main text, sometimes to the right, and I couldn't sense any reason for the inconsistencies. Eventually, I just learned to ignore the formatting, which is sort of a shame; formatting in a book, just like code formatting, should help the reader take in the structure at a glance, not make us wonder what's going on.
All told, Higher Order Perl is a tremendous book, and confirms the notion that Perl is All Grown Up. It can do tricks that most other languages can only dream about, and Mark Jason Dominus is eager to show us how.
TPJ