Saturday, May 3, 2008

Which programming language is the most X?

Mailing lists are great places to find fruitless arguments. One of the most chronic arguments take the form of "My programming language is the most X". Here X may be "object-oriented", "functional", or even something much vaguer like "elegant".

When using terms like "object-oriented" and "functional" it is good to have somewhat agreed upon definitions. A characteristic that applies to everything applies to nothing. This is why I get a little bit frustrated when I read arguments like C is object-oriented because you can create tables of function pointers to simulate polymorphism or C is functional because you can pass a pointer to a function. We'll then so is assembler, I guess.

However, almost as annoying are arguments within the group of languages that are widely agreed to have the specified trait. Consider functional languages. I think present day functional enthusiasts would agree that Haskell is an outstanding example of a functional language. It has first class functions, lambda abstraction, and higher order primitives like map, foldr, foldl, etc. However, things begin to go awry when Haskellers start conflating features of the language that, although virtuous as they may be, evolved after the functional paradigm became widely recognised. For example, take single assignment. Clearly single assignment has many benefits. But it is hard for me to accept that the mother of all functional languages, Lisp, is not functional because it has setq. The same is true for other traits like currying, closures, type induction, lazy evaluation, etc.

What gets lost in the quest to define a language as the most X is the much harder question of why the traits that one deems must exist in a X language are important in the first place. In which circumstances will such a trait lead to better software and in which circumstances will it simply provide rope to hang oneself.

The distinction between strict and non-strict functional languages is a good case in point. In a strict language the arguments passed to a function must be fully evaluated before the invocation (ML, Scheme) while non-strict languages can support lazy evaluation (Miranda, Haskell). Is a non-strict language better than a strict one? Should languages support both? Are such questions even answerable?

I think these questions are important and are answerable but the answers involve very deep considerations of problem domain, proofs of correctness, type theory, compiler design and even the limitations of human ability to reason about software. Human knowledge in these areas are not extended by arguments about what's more X.

1 comment:

Kalani said...

Good post Sal, I completely agree that those kinds of oversimplified absolutist flamewars are useless. If you're going to fight over whether or not a language is functional (or OO), you might as well fight over how many angels can dance on the head of a pin.

The world of PLT is a lot more subtle and interesting than that, in my opinion. That's why it's important to consider the "cost structure" of fine-grained language features in the context of a specific problem (or problem category). TANSTAAFL.

I think that this essay by John Hughes is a great example of presenting language features in small parts, and evaluating them one-by-one:

http://www.cs.chalmers.se/~rjmh/Papers/whyfp.html

As for single-assignment and compiler-writing, somewhere there's a great short essay by Andrew Appel about the equivalence of the SSA and CPS intermediate forms.