Wednesday 16 September 2009

Innovation in programming languages mess up the syntax

The amount of new features that go into programming languages these days, is extraordinary. There is no doubt, that the demand for multi-core programming requires innovation, but the widespread use of garbage collection also introduces new possibilities, like LINQ. Few programming tools introduce new methods at the same pace as Delphi Prism.

We may see a kind of survival of the fittest amongst all the methods, making some features survive and other not. I'm not sure that the parallel keyword in Delphi Prism has a great future - simply because parallelism shouldn't be done on a low level but on a high level, which is already nicely supported using anonymous methods. It's a kind of race, where errors are made, and one of the biggest errors is probably that many of the features introduce complexity in the language syntax, raising the learning barrier for new programmers. Personally, I very much dislike the use of "+=" for adding a handler in .net, simply because "+=" does not contain any explanatory information, like letters would. It gets much worse when you want to remove a handler, where you use "-= new". It is not intuitive to remove a handler by creating an object. If operators can be used for anything, why limit yourself to operators that already exist? Why not introduce a new "+==+" operator for something? It reminds me of the international obfuscated C code programming contest. Aspect Oriented Programming, LINQ, .net lambda expressions etc. all introduce new syntax elements, that don't look like things we have seen before. When some of these new features eventually become less used, we still have to support them, just like the "object" keyword is still supported by Delphi, even though OOP was changed with Delphi 1.

Anonymous methods and many of the new features are really cool, but in a few years it will likely be possible to design new, simple programming languages from scratch, which implement the most used features in a much nicer way. It may even be possible to create a low-complexity language like PHP or Python, that performs well and has most of these new features, is cross platform etc., becoming the preferred choice for new programmers. It will be interesting to see how programming language support for NUMA will evolve, when one piece of data cannot be accessed equally well by all threads in your app.


Caleb Hattingh said...

In light of your comment

"It may even be possible to create a low-complexity language like PHP or Python, that performs well and has most of these new features, is cross platform etc., becoming the preferred choice for new programmers."

What do you think of Paul Graham's observation that all languages are gradually becoming lisp? In particular, lisp already is low-complexity [the entire syntax is of the form (function argument)], is cross-platform, and has distributions that perform very well?

My own take is that Python is popular because its development prioritizes ruthless pragmatism; the two key examples of this are:

a) The syntax makes it easier than most other languages to read and write code;

b) Batteries are included, meaning that the bulk of most-needed libraries are packaged in the mainline downloadable distribution.

The debate between pragmatism (e.g. C, Java, Delphi, Python) and purity (Lisp, Scheme, Haskell) is an interesting one. Are the two goals opposing or orthogonal?

QbProg said...

The best example of this "mess" is C++0x :) Never seen a syntax bad like c++ lambdas!

Anonymous said...

I'd have to disagree with Paul Graham's interpretation of the facts. Yes, other programming languages are incorporating features that Lisp pioneered, but not because they're somehow evolving to become more like Lisp, but because Lisp needed them first.

Lisp was intended as a better computational model than traditional imperative programming that's written directly to the Turing Machine model. Basically the creators wanted to reinvent not only the wheel but the entire car. Thing is, they had to introduce all sorts of new, complex constructs in order to make it able to do anything useful, since the design of the language they came up with was so alien to the way the Turing Machine-equivalent hardware they were running on did business.

Some of the new ideas have been very good, (if-then-else, function pointers), some were really bad (garbage collection!), and some were just plain bizarre (code as data, S-expression syntax.)

According to Paul Graham, these bizarre features are "so far still unique to Lisp, perhaps because (a) it requires those parens, or something just as bad, and (b) if you add that final increment of power, you can no longer claim to have invented a new language, but only to have designed a new dialect of Lisp".

And he's right. It's the bizarre, completely-alien-to-how-a-computer-actually-works stuff that is the original core of Lisp. All the other innovations were invented to support those borderline-insane concepts and make a functioning programming language out of it. And I don't really see other languages copying them, because they already work just fine without them.

Caleb Hattingh said...


I don't know if you would also consider python to exhibit "borderline insane concepts" (I hope not; if so your criterion for insanity is overtly aggressive) but bear with me:

The primary difference between python and lisp is "code-is-data-is-code", i.e. runtime macros. It is still possible to do with python, but the AST is very much more difficult to deal with than lisp, precisely because lisp has a uniform syntax. It is the syntax of lisp that allows it to do macros more efficiently than other systems.

That's it. There is no other (real) difference. Now having said that, are macros worthwhile? Since they lie in the direction of increasing abstraction I am compelled to say yes.

Are they practical? That is a much tougher question and depends on a whole host of factors; a common factor is that very few people are familiar with writing recursive code in S-expressions, so that is usually the show-stopper right there.

But I cannot agree that the mere concept of runtime macro expansion is insane at all; at most, only unfamiliar.

(By the way, lisp has *fewer* complex constructs than most other languages. That is something you should be careful not to repeat in less friendlier environments)