January 29, 2007 — jao

Learning about functional and dynamic languages is a doubled-edged sword. On the one hand, it opens up your mind and ensures many hours of really happy, even enlightened, hacking. But, on the other hand, it spoils you: if you ever have to come back to, say, C or Java programming you may get frustrated by the limitations you’ll find [0]. On the bright side, once you get over the first symptoms of impatience, knowing about better ways of coding will improve your programs in any language. I’ve been using mainly C at work during the last year and a half, and i feel that the quality of the code i write has been greatly improved by my readings on Lisp, Haskell and the like.

Ultimately, it’s not about the language you use or its syntax, but about how you think about your problems. And more about the tools and structures in your mind than in your language: if you have the former, you can usually work around deficiencies in the latter. But still, there has been many a time during the last months that i’ve wished i had been using, say, Scheme. For, although i knew how to reproduce the feature i needed using C, re-implementing it would have been too time-consuming. In this regard, using the most flexible language at your disposal may be a good idea.

For instance, i was reading an article entitled Generalized Function Pointers, which describes a C++ library for handling higher-order functions. For starters, it makes an interesting description of the kind of problems you find in languages with no built-in support for closures and HOFs. It may convince you (if needed) of why they’re a good thing to have. The good news if you’re using C++ is that there’s a boost library, Boost.Function, that implements polymorphic function object wrappers, and lets you write code like this:

function<int (int x, int y)> arithmetic_operation(char k) { switch (k) { case '+': return plus<int>(); case '-': return minus<int>(); case '*': return multiplies<int>(); case '/': return divides<int>(); case '%': return modulus<int>(); default: assert(0); } }

Not as pretty as Scheme or Haskell, but my point is that, at least, C++ let’s you get closer to the real thing, which is more than C or Java can do [1]. I’ll left it for you to ponder whether the drawbacks of C++ surpass niceties as this one: i’m considering the (not unlikely) scenario where you need to use one of these languages, for whatever reason. Which leads me to my second, and more important, point: had i not studied functional languages, i wouldn’t be in a position to really appreciate and take profit of libraries such as those in boost’s functional and generic programming collections [2], or the excellent FC++. And would have lost lots of fun.

—

[0] I’m sure he’s exaggerating a bit, but Eric’s recent report of his first month using Haskell vividly expresses this kind of feeling:

For me, it’s a drug. The more Haskell I get, the more I want. The results I’m getting right now aren’t orders of magnitude better than the results I can get in a von Neumann language, but the velocity I can achieve is astounding. (When I’m not dealing with stupid extraneous problems.)

[1] Yes, i know you can do similar things in C or Java, but Boost.Function is more powerful than that (the keyword here being ‘polymorphic’, meaning, essentially, that it handles covariant and contravariant signatures gracefully).

[2] For more on the kind of tricks one can play using templates and Boost.Function, see Sutter’s Generalizing Observer, where the author, essentially, works around the lack of multi-methods in C++. More to the point, that article will make much more sense once one learns a bit of, for instance, Common Lisp’s object model.